home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet internetowy / Rozne / HTTrack 3.40-2 / httrack-3.40-2.exe / {app} / src / htslib.c < prev    next >
C/C++ Source or Header  |  2006-04-09  |  144KB  |  5,184 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Subroutines                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. /* Internal engine bytecode */
  38. #define HTS_INTERNAL_BYTECODE
  39.  
  40. // Fichier librairie .c
  41.  
  42. #include "htslib.h"
  43. #include "htsbauth.h"
  44.  
  45. #ifdef _WIN32_WCE
  46. #ifndef HTS_CECOMPAT
  47. #pragma comment(lib, "celib.lib") //link with celib
  48. #endif
  49. #endif
  50.  
  51. /* specific definitions */
  52. #include "htsbase.h"
  53. #include "htsnet.h"
  54. #include "htsbauth.h"
  55. #include "htsthread.h"
  56. #include "htsnostatic.h"
  57. #include "htswrap.h"
  58. #include "htsmd5.h"
  59. #if HTS_WIN
  60. #ifndef  _WIN32_WCE
  61. #include <direct.h>
  62. #endif
  63. #else
  64. #ifdef HAVE_SYS_TYPES_H
  65. #include <sys/types.h>
  66. #endif
  67. #ifdef HAVE_SYS_STAT_H
  68. #include <sys/stat.h>
  69. #endif
  70. #ifdef HAVE_UNISTD_H
  71. #include <unistd.h>
  72. #endif
  73. #endif
  74. #include <string.h>
  75. #include <time.h>
  76. #ifndef  _WIN32_WCE
  77. #include <sys/timeb.h>
  78. #else
  79. #ifndef HTS_CECOMPAT
  80. #include <sys/timeb.h>
  81. #endif
  82. #endif
  83. #ifndef _WIN32_WCE
  84. #include <fcntl.h>
  85. #endif
  86. // pour utimbuf
  87. #if HTS_WIN
  88. #ifndef _WIN32_WCE
  89. #include <sys/utime.h>
  90. #else
  91. #ifndef HTS_CECOMPAT
  92. #include <sys/utime.h>
  93. #endif
  94. #endif
  95. #else
  96. #include <utime.h>
  97. #endif
  98. #ifndef _WIN32_WCE
  99. #include <sys/stat.h>
  100. #endif
  101. /* END specific definitions */
  102.  
  103.  
  104. // Debugging
  105. #if _HTS_WIDE
  106. FILE* DEBUG_fp=NULL;
  107. #endif
  108.  
  109. /* variables globales */
  110. int _DEBUG_HEAD;
  111. FILE* ioinfo;
  112.  
  113. #if HTS_USEOPENSSL
  114.  SSL_CTX *openssl_ctx = NULL;
  115. #endif
  116. int IPV6_resolver = 0;
  117.  
  118.  
  119. /* dΘtection complΘmentaire */
  120. const char* hts_detect[] = {
  121.   "archive",
  122.   "background",
  123.   "data",         // OBJECT
  124.   "dynsrc",
  125.   "lowsrc",
  126.   "profile",      // element META
  127.   "src",
  128.   "swurl",
  129.   "url",
  130.   "usemap",
  131.   "longdesc",     // accessibility
  132.   "xlink:href",   // xml/svg tag
  133.   ""
  134. };
  135.  
  136. /* dΘtecter dΘbut */
  137. const char* hts_detectbeg[] = {
  138.   "hotspot",      /* hotspot1=..,hotspot2=.. */
  139.   ""
  140. };
  141.  
  142. /* ne pas dΘtcter de liens dedans */
  143. const char* hts_nodetect[] = {
  144.   "accept-charset",
  145.   "accesskey",
  146.   "action",
  147.   "align",
  148.   "alt",
  149.   "axes",
  150.   "axis",
  151.   "char",
  152.   "charset",
  153.   "cite",
  154.   "class",
  155.   "classid",
  156.   "code",
  157.   "color",
  158.   "datetime",
  159.   "dir",
  160.   "enctype",
  161.   "face",
  162.   "height",
  163.   "id",
  164.   "lang",
  165.   "language",
  166.   "media",
  167.   "method",
  168.   "name",
  169.   "prompt",
  170.   "scheme",
  171.   "size",
  172.   "style",
  173.   "target",
  174.   "title",
  175.   "type",
  176.   "valign",
  177.   "version",
  178.   "width",
  179.   ""
  180. };
  181.  
  182.  
  183. /* dΘtection de mini-code javascript */
  184. /* ALSO USED: detection based on the name: onXXX="<tag>" where XXX starts with upper case letter */
  185. const char* hts_detect_js[] = {
  186.   "onAbort",
  187.   "onBlur",
  188.   "onChange",
  189.   "onClick",
  190.   "onDblClick",
  191.   "onDragDrop",
  192.   "onError",
  193.   "onFocus",
  194.   "onKeyDown",
  195.   "onKeyPress",
  196.   "onKeyUp",
  197.   "onLoad",
  198.   "onMouseDown",
  199.   "onMouseMove",
  200.   "onMouseOut",
  201.   "onMouseOver",
  202.   "onMouseUp",
  203.   "onMove",
  204.   "onReset",
  205.   "onResize",
  206.   "onSelect",
  207.   "onSubmit",
  208.   "onUnload",
  209.   "style",          /* hack for CSS code data */
  210.   ""
  211. };
  212.  
  213. const char* hts_main_mime[] = {
  214.   "application",
  215.   "audio",
  216.   "image",
  217.   "message",
  218.   "multipart",
  219.   "text",
  220.   "video",
  221.   ""
  222. };
  223.  
  224. /* dΘtection "...URL=<url>" */
  225. const char* hts_detectURL[] = {
  226.   "content",
  227.   ""
  228. };
  229.  
  230. /* tags o∙ l'URL doit Ωtre rΘΘcrite mais non capturΘe */
  231. const char* hts_detectandleave[] = {
  232.   "action",
  233.   ""
  234. };
  235.  
  236. /* ne pas renommer les types renvoyΘs (souvent types inconnus) */
  237. const char* hts_mime_keep[] = {
  238.   "application/octet-stream",
  239.   "text/plain",
  240.   ""
  241. };
  242.  
  243. /* pas de type mime connu, mais extension connue */
  244. const char* hts_ext_dynamic[] = {
  245.   "php3",
  246.   "php",
  247.   "php4",
  248.   "php2",
  249.   "cgi",
  250.   "asp",
  251.   "jsp",
  252.   "pl",
  253.   /*"exe",*/
  254.   "cfm",
  255.   "nsf", /* lotus */
  256.   ""
  257. };
  258.  
  259. /* types MIME 
  260.    note: application/octet-stream should not be used here
  261. */
  262. const char* hts_mime[][2] = {
  263.   {"application/acad","dwg"},
  264.   {"application/arj","arj"},
  265.   {"application/clariscad","ccad"},
  266.   {"application/drafting","drw"},
  267.   {"application/dxf","dxf"},
  268.   {"application/excel","xls"},
  269.   {"application/i-deas","unv"},
  270.   {"application/iges","isg"},
  271.   {"application/iges","iges"},
  272.   {"application/mac-binhex40","hqx"},
  273.   {"application/mac-compactpro","cpt"},
  274.   {"application/msword","doc"},
  275.   {"application/msword","w6w"},
  276.   {"application/msword","word"},
  277.   {"application/mswrite","wri"},
  278.   /*{"application/octet-stream","dms"},*/
  279.   /*{"application/octet-stream","lzh"},*/
  280.   /*{"application/octet-stream","lha"},*/
  281.   /*{"application/octet-stream","bin"},*/
  282.   {"application/oda","oda"},
  283.   {"application/pdf","pdf"},
  284.   {"application/postscript","ps"},
  285.   {"application/postscript","ai"},
  286.   {"application/postscript","eps"},
  287.   {"application/powerpoint","ppt"},
  288.   {"application/pro_eng","prt"},
  289.   {"application/pro_eng","part"},
  290.   {"application/rtf","rtf"},
  291.   {"application/set","set"},
  292.   {"application/sla","stl"},
  293.   {"application/smil","smi"},
  294.   {"application/smil","smil"},
  295.   {"application/smil","sml"},
  296.   {"application/solids","sol"},
  297.   {"application/STEP","stp"},
  298.   {"application/STEP","step"},
  299.   {"application/vda","vda"},
  300.   {"application/x-authorware-map","aam"},     
  301.   {"application/x-authorware-seg","aas"},
  302.   {"application/x-authorware-bin","aab"},
  303.   {"application/x-cocoa","cco"},
  304.   {"application/x-csh","csh"},
  305.   {"application/x-director","dir"},
  306.   {"application/x-director","dcr"},
  307.   {"application/x-director","dxr"},
  308.   {"application/x-mif","mif"},
  309.   {"application/x-dvi","dvi"},
  310.   {"application/x-gzip","gz"},
  311.   {"application/x-gzip","gzip"},
  312.   {"application/x-hdf","hdf"},
  313.   {"application/x-javascript","js"},
  314.   {"application/x-koan","skp"},
  315.   {"application/x-koan","skd"},
  316.   {"application/x-koan","skt"},
  317.   {"application/x-koan","skm"},
  318.   {"application/x-latex","latex"},
  319.   {"application/x-netcdf","nc"},
  320.   {"application/x-netcdf","cdf"},
  321.   /* {"application/x-sh","sh"}, */
  322.   /* {"application/x-csh","csh"}, */
  323.   /* {"application/x-ksh","ksh"}, */
  324.   {"application/x-shar","shar"},
  325.   {"application/x-stuffit","sit"},
  326.   {"application/x-tcl","tcl"},
  327.   {"application/x-tex","tex"},
  328.   {"application/x-texinfo","texinfo"},
  329.   {"application/x-texinfo","texi"},
  330.   {"application/x-troff","t"},
  331.   {"application/x-troff","tr"},
  332.   {"application/x-troff","roff"},
  333.   {"application/x-troff-man","man"},
  334.   {"application/x-troff-me","ms"},
  335.   {"application/x-wais-source","src"},
  336.   {"application/zip","zip"},
  337.   {"application/x-zip-compressed","zip"},
  338.   {"application/x-bcpio","bcpio"},
  339.   {"application/x-cdlink","vcd"},
  340.   {"application/x-cpio","cpio"},
  341.   {"application/x-gtar","tgz"},
  342.   {"application/x-gtar","gtar"},
  343.   {"application/x-shar","shar"},
  344.   {"application/x-shockwave-flash","swf"},
  345.   {"application/x-sv4cpio","sv4cpio"},
  346.   {"application/x-sv4crc","sv4crc"},
  347.   {"application/x-tar","tar"},
  348.   {"application/x-ustar","ustar"},
  349.   {"application/x-winhelp","hlp"},
  350.   {"audio/midi","mid"},
  351.   {"audio/midi","midi"},
  352.   {"audio/midi","kar"},
  353.   {"audio/mpeg","mp3"},
  354.   {"audio/mpeg","mpga"},
  355.   {"audio/mpeg","mp2"},
  356.   {"audio/basic","au"},
  357.   {"audio/basic","snd"},
  358.   {"audio/x-aiff","aif"},
  359.   {"audio/x-aiff","aiff"},
  360.   {"audio/x-aiff","aifc"},
  361.   {"audio/x-pn-realaudio","rm"},
  362.   {"audio/x-pn-realaudio","ram"},
  363.   {"audio/x-pn-realaudio","ra"},
  364.   {"audio/x-pn-realaudio-plugin","rpm"},
  365.   {"audio/x-wav","wav"},
  366.   {"chemical/x-pdb","pdb"},
  367.   {"chemical/x-pdb","xyz"},
  368.   {"drawing/x-dwf","dwf"},
  369.   {"image/gif","gif"},
  370.   {"image/ief","ief"},
  371.   {"image/jpeg","jpg"},
  372.   {"image/jpeg","jpe"},
  373.   {"image/jpeg","jpeg"},
  374.   {"image/pict","pict"},
  375.   {"image/png","png"},
  376.   {"image/tiff","tiff"},
  377.   {"image/tiff","tif"},
  378.   {"image/svg+xml","svg"},
  379.   {"image/svg-xml","svg"},
  380.   {"image/x-cmu-raster","ras"},
  381.   {"image/x-freehand","fh4"},
  382.   {"image/x-freehand","fh7"},
  383.   {"image/x-freehand","fh5"},  
  384.   {"image/x-freehand","fhc"},
  385.   {"image/x-freehand","fh"},   
  386.   {"image/x-portable-anymap","pnm"},
  387.   {"image/x-portable-bitmap","pgm"},
  388.   {"image/x-portable-pixmap","ppm"},
  389.   {"image/x-rgb","rgb"},
  390.   {"image/x-xbitmap","xbm"},
  391.   {"image/x-xpixmap","xpm"},
  392.   {"image/x-xwindowdump","xwd"},
  393.   {"model/mesh","msh"},  
  394.   {"model/mesh","mesh"},  
  395.   {"model/mesh","silo"},  
  396.   {"multipart/x-zip","zip"},
  397.   {"multipart/x-gzip","gzip"},
  398.   {"text/css","css"},
  399.   {"text/html","html"},
  400.   {"text/html","htm"},
  401.   {"text/plain","txt"},
  402.   {"text/plain","g"},
  403.   {"text/plain","h"},
  404.   {"text/plain","c"},
  405.   {"text/plain","cc"},
  406.   {"text/plain","hh"},
  407.   {"text/plain","m"},
  408.   {"text/plain","f90"},
  409.   {"text/richtext","rtx"},
  410.   {"text/tab-separated-values","tsv"},
  411.   {"text/x-setext","etx"},
  412.   {"text/x-sgml","sgml"},
  413.   {"text/x-sgml","sgm"},
  414.   {"text/xml","xml"},  
  415.   {"text/xml","dtd"},  
  416.   {"video/mpeg","mpeg"},
  417.   {"video/mpeg","mpg"},
  418.   {"video/mpeg","mpe"},
  419.   {"video/quicktime","qt"},
  420.   {"video/quicktime","mov"},
  421.   {"video/x-msvideo","avi"},
  422.   {"video/x-sgi-movie","movie"},
  423.   {"x-conference/x-cooltalk","ice"},
  424.   /*{"application/x-httpd-cgi","cgi"},*/
  425.   {"x-world/x-vrml","wrl"},
  426.  
  427.   /* More from w3schools.com */
  428.   { "application/envoy", "evy" },
  429.   { "application/fractals", "fif" },
  430.   { "application/futuresplash", "spl" },
  431.   { "application/hta", "hta" },
  432.   { "application/internet-property-stream", "acx" },
  433.   { "application/msword", "dot" },
  434.   { "application/olescript", "axs" },
  435.   { "application/pics-rules", "prf" },
  436.   { "application/pkcs10", "p10" },
  437.   { "application/pkix-crl", "crl" },
  438.   { "application/set-payment-initiation", "setpay" },
  439.   { "application/set-registration-initiation", "setreg" },
  440.   { "application/vnd.ms-excel", "xla" },
  441.   { "application/vnd.ms-excel", "xlc" },
  442.   { "application/vnd.ms-excel", "xlm" },
  443.   { "application/vnd.ms-excel", "xls" },
  444.   { "application/vnd.ms-excel", "xlt" },
  445.   { "application/vnd.ms-excel", "xlw" },
  446.   { "application/vnd.ms-pkicertstore", "sst" },
  447.   { "application/vnd.ms-pkiseccat", "cat" },
  448.   { "application/vnd.ms-powerpoint", "pot" },
  449.   { "application/vnd.ms-powerpoint", "pps" },
  450.   { "application/vnd.ms-powerpoint", "ppt" },
  451.   { "application/vnd.ms-project", "mpp" },
  452.   { "application/vnd.ms-works", "wcm" },
  453.   { "application/vnd.ms-works", "wdb" },
  454.   { "application/vnd.ms-works", "wks" },
  455.   { "application/vnd.ms-works", "wps" },
  456.   { "application/x-compress", "z" },
  457.   { "application/x-compressed", "tgz" },
  458.   { "application/x-internet-signup", "ins" },
  459.   { "application/x-internet-signup", "isp" },
  460.   { "application/x-iphone", "iii" },
  461.   { "application/x-javascript", "js" },
  462.   { "application/x-msaccess", "mdb" },
  463.   { "application/x-mscardfile", "crd" },
  464.   { "application/x-msclip", "clp" },
  465.   { "application/x-msmediaview", "m13" },
  466.   { "application/x-msmediaview", "m14" },
  467.   { "application/x-msmediaview", "mvb" },
  468.   { "application/x-msmetafile", "wmf" },
  469.   { "application/x-msmoney", "mny" },
  470.   { "application/x-mspublisher", "pub" },
  471.   { "application/x-msschedule", "scd" },
  472.   { "application/x-msterminal", "trm" },
  473.   { "application/x-perfmon", "pma" },
  474.   { "application/x-perfmon", "pmc" },
  475.   { "application/x-perfmon", "pml" },
  476.   { "application/x-perfmon", "pmr" },
  477.   { "application/x-perfmon", "pmw" },
  478.   { "application/x-pkcs12", "p12" },
  479.   { "application/x-pkcs12", "pfx" },
  480.   { "application/x-pkcs7-certificates", "p7b" },
  481.   { "application/x-pkcs7-certificates", "spc" },
  482.   { "application/x-pkcs7-certreqresp", "p7r" },
  483.   { "application/x-pkcs7-mime", "p7c" },
  484.   { "application/x-pkcs7-mime", "p7m" },
  485.   { "application/x-pkcs7-signature", "p7s" },
  486.   { "application/x-troff-me", "me" },
  487.   { "application/x-x509-ca-cert", "cer" },
  488.   { "application/x-x509-ca-cert", "crt" },
  489.   { "application/x-x509-ca-cert", "der" },
  490.   { "application/ynd.ms-pkipko", "pko" },
  491.   { "audio/mid", "mid" },
  492.   { "audio/mid", "rmi" },
  493.   { "audio/mpeg", "mp3" },
  494.   { "audio/x-mpegurl", "m3u" },
  495.   { "image/bmp", "bmp" },
  496.   { "image/cis-cod", "cod" },
  497.   { "image/pipeg", "jfif" },
  498.   { "image/x-cmx", "cmx" },
  499.   { "image/x-icon", "ico" },
  500.   { "image/x-portable-bitmap", "pbm" },
  501.   { "message/rfc822", "mht" },
  502.   { "message/rfc822", "mhtml" },
  503.   { "message/rfc822", "nws" },
  504.   { "text/css", "css" },
  505.   { "text/h323", "323" },
  506.   { "text/html", "stm" },
  507.   { "text/iuls", "uls" },
  508.   { "text/plain", "bas" },
  509.   { "text/scriptlet", "sct" },
  510.   { "text/webviewhtml", "htt" },
  511.   { "text/x-component", "htc" },
  512.   { "text/x-vcard", "vcf" },
  513.   { "video/mpeg", "mp2" },
  514.   { "video/mpeg", "mpa" },
  515.   { "video/mpeg", "mpv2" },
  516.   { "video/x-la-asf", "lsf" },
  517.   { "video/x-la-asf", "lsx" },
  518.   { "video/x-ms-asf", "asf" },
  519.   { "video/x-ms-asf", "asr" },
  520.   { "video/x-ms-asf", "asx" },
  521.   { "x-world/x-vrml", "flr" },
  522.   { "x-world/x-vrml", "vrml" },
  523.   { "x-world/x-vrml", "wrz" },
  524.   { "x-world/x-vrml", "xaf" },
  525.   { "x-world/x-vrml", "xof" },
  526.  
  527.   /* Various */
  528.   { "application/ogg", "ogg" },
  529.  
  530.   {"*","class"},
  531.   
  532.   {"",""}};
  533.  
  534.  
  535. // Reserved (RFC2396)
  536. #define CIS(c,ch) ( ((unsigned char)(c)) == (ch) )
  537. #define CHAR_RESERVED(c)  ( CIS(c,';') \
  538.                          || CIS(c,'/') \
  539.                          || CIS(c,'?') \
  540.                          || CIS(c,':') \
  541.                          || CIS(c,'@') \
  542.                          || CIS(c,'&') \
  543.                          || CIS(c,'=') \
  544.                          || CIS(c,'+') \
  545.                          || CIS(c,'$') \
  546.                          || CIS(c,',') )
  547. //#define CHAR_RESERVED(c)  ( strchr(";/?:@&=+$,",(unsigned char)(c)) != 0 )
  548. // Delimiters (RFC2396)
  549. #define CHAR_DELIM(c)     ( CIS(c,'<') \
  550.                          || CIS(c,'>') \
  551.                          || CIS(c,'#') \
  552.                          || CIS(c,'%') \
  553.                          || CIS(c,'\"') )
  554. //#define CHAR_DELIM(c)     ( strchr("<>#%\"",(unsigned char)(c)) != 0 )
  555. // Unwise (RFC2396)
  556. #define CHAR_UNWISE(c)    ( CIS(c,'{') \
  557.                          || CIS(c,'}') \
  558.                          || CIS(c,'|') \
  559.                          || CIS(c,'\\') \
  560.                          || CIS(c,'^') \
  561.                          || CIS(c,'[') \
  562.                          || CIS(c,']') \
  563.                          || CIS(c,'`') )
  564. //#define CHAR_UNWISE(c)    ( strchr("{}|\\^[]`",(unsigned char)(c)) != 0 )
  565. // Special (escape chars) (RFC2396 + >127 )
  566. #define CHAR_LOW(c)       ( ((unsigned char)(c) <= 31) )
  567. #define CHAR_HIG(c)       ( ((unsigned char)(c) >= 127) )
  568. #define CHAR_SPECIAL(c)   ( CHAR_LOW(c) || CHAR_HIG(c) )
  569. // We try to avoid them and encode them instead
  570. #define CHAR_XXAVOID(c)   ( CIS(c,' ') \
  571.                          || CIS(c,'*') \
  572.                          || CIS(c,'\'') \
  573.                          || CIS(c,'\"') \
  574.                          || CIS(c,'&') \
  575.                          || CIS(c,'!') )
  576. //#define CHAR_XXAVOID(c)   ( strchr(" *'\"!",(unsigned char)(c)) != 0 )
  577. #define CHAR_MARK(c)      ( CIS(c,'-') \
  578.                          || CIS(c,'_') \
  579.                          || CIS(c,'.') \
  580.                          || CIS(c,'!') \
  581.                          || CIS(c,'~') \
  582.                          || CIS(c,'*') \
  583.                          || CIS(c,'\'') \
  584.                          || CIS(c,'(') \
  585.                          || CIS(c,')') )
  586. //#define CHAR_MARK(c)      ( strchr("-_.!~*'()",(unsigned char)(c)) != 0 )
  587.  
  588.  
  589.  
  590. // conversion Θventuelle / vers antislash
  591. #if HTS_WIN
  592. char* antislash(char* s) {
  593.   char* buff;
  594.   char* a;
  595.   NOSTATIC_RESERVE(buff, char, HTS_URLMAXSIZE*2);
  596.  
  597.   strcpybuff(buff,s);
  598.   while(a=strchr(buff,'/')) *a='\\';
  599.   return buff;
  600. }
  601. #endif
  602.  
  603. #ifdef _WIN32_WCE
  604. char cwd[MAX_PATH+1] = "";
  605. #endif
  606.  
  607. // RΘcupΘration d'un fichier http sur le net.
  608. // Renvoie une adresse sur le bloc de mΘmoire, ou bien
  609. // NULL si un retour.msgeur (buffer retour.msg) est survenue. 
  610. //
  611. // Une adresse de structure htsmsg peut Ωtre transmise pour
  612. // suivre l'Θvolution du chargement si le process a ΘtΘ lancΘ 
  613. // en background
  614.  
  615. htsblk httpget(char* url) {
  616.   char BIGSTK adr[HTS_URLMAXSIZE*2];   // adresse
  617.   char BIGSTK fil[HTS_URLMAXSIZE*2];   // chemin
  618.   
  619.   // sΘparer URL en adresse+chemin
  620.   if (ident_url_absolute(url,adr,fil)==-1) {
  621.     htsblk retour;
  622.     memset(&retour, 0, sizeof(htsblk));    // effacer
  623.     // retour prΘdΘfini: erreur
  624.     retour.adr=NULL;
  625.     retour.size=0;
  626.     retour.msg[0]='\0';
  627.     retour.statuscode=STATUSCODE_INVALID;    
  628.     strcpybuff(retour.msg,"Error invalid URL");
  629.     return retour;
  630.   }
  631.   
  632.   return xhttpget(adr,fil);
  633. }
  634.  
  635. // ouvre une liaison http, envoie une requΦte GET et rΘceptionne le header
  636. // retour: socket
  637. int http_fopen(char* adr,char* fil,htsblk* retour) {
  638.   //                / GET, traiter en-tΩte
  639.   return http_xfopen(0,1,1,NULL,adr,fil,retour);
  640. }
  641.  
  642. // ouverture d'une liaison http, envoi d'une requΦte
  643. // mode: 0 GET  1 HEAD  [2 POST]
  644. // treat: traiter header?
  645. // waitconnect: attendre le connect()
  646. // note: dans retour, on met les params du proxy
  647. int http_xfopen(int mode,int treat,int waitconnect,char* xsend,char* adr,char* fil,htsblk* retour) {
  648.   //htsblk retour;
  649.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  650.   T_SOC soc=INVALID_SOCKET;
  651.   //char *p,*q;
  652.   
  653.   // retour prΘdΘfini: erreur
  654.   if (retour) {
  655.     retour->adr=NULL;
  656.     retour->size=0;
  657.     retour->msg[0]='\0';
  658.     retour->statuscode=STATUSCODE_NON_FATAL;          // a priori erreur non fatale
  659.   }
  660.  
  661. #if HDEBUG
  662.   printf("adr=%s\nfichier=%s\n",adr,fil);
  663. #endif
  664.   
  665.   // ouvrir liaison
  666. #if HDEBUG
  667.   printf("CrΘation d'une socket sur %s\n",adr);
  668. #endif
  669.  
  670. #if CNXDEBUG
  671.   printf("..newhttp\n");
  672. #endif
  673.  
  674.   /* connexion */
  675.   if (retour) {
  676.     if ( (!(retour->req.proxy.active)) 
  677.       ||
  678.       (
  679.         (strcmp(adr,"file://")==0) 
  680.         ||
  681.         (strncmp(adr,"https://", 8)==0) 
  682.       )
  683.       ) {    /* pas de proxy, ou non utilisable ici */
  684.       soc=newhttp(adr,retour,-1,waitconnect);
  685.     } else {
  686.       soc=newhttp(retour->req.proxy.name,retour,retour->req.proxy.port,waitconnect);  // ouvrir sur le proxy α la place
  687.     }
  688.   } else {
  689.     soc=newhttp(adr,NULL,-1,waitconnect);    
  690.   }
  691.  
  692.   // copier index socket retour
  693.   if (retour) retour->soc=soc;
  694.  
  695.   /* Check for errors */
  696.   if (soc == INVALID_SOCKET) {
  697.     if (retour) {
  698.       if (retour->msg) {
  699.         if (!strnotempty(retour->msg)) {
  700. #ifdef _WIN32
  701.           sprintf(retour->msg,"Connect error: %s", strerror(WSAGetLastError()));
  702. #else
  703.           sprintf(retour->msg,"Connect error: %s", strerror(errno));
  704. #endif
  705.         }
  706.       }
  707.     }
  708.   }
  709.  
  710.   // --------------------
  711.   // court-circuit (court circuite aussi le proxy..)
  712.   // LOCAL_SOCKET_ID est une pseudo-socket locale
  713.   if (soc==LOCAL_SOCKET_ID) {
  714.     retour->is_file=1;  // fichier local
  715.     if (mode==0) {    // GET
  716.  
  717.       // Test en cas de file:///C|...
  718.       if (!fexist(fconv(unescape_http(fil))))
  719.         if (fexist(fconv(unescape_http(fil+1)))) {
  720.           char BIGSTK tempo[HTS_URLMAXSIZE*2];
  721.           strcpybuff(tempo,fil+1);
  722.           strcpybuff(fil,tempo);
  723.         }
  724.  
  725.       // Ouvrir
  726.       retour->totalsize=fsize(fconv(unescape_http(fil)));  // taille du fichier
  727.       retour->msg[0]='\0';
  728.       soc=INVALID_SOCKET;
  729.       if (retour->totalsize<0)
  730.         strcpybuff(retour->msg,"Unable to open local file");
  731.       else if (retour->totalsize==0)
  732.         strcpybuff(retour->msg,"File empty");
  733.       else {
  734.         // Note: On passe par un FILE* (plus propre)
  735.         //soc=open(fil,O_RDONLY,0);    // en lecture seule!
  736.         retour->fp=fopen(fconv(unescape_http(fil)),"rb");  // ouvrir
  737.         if (retour->fp==NULL)
  738.           soc=INVALID_SOCKET;
  739.         else
  740.           soc=LOCAL_SOCKET_ID;
  741.       }
  742.       retour->soc=soc;
  743.       if (soc!=INVALID_SOCKET) {
  744.         retour->statuscode=200;   // OK
  745.         strcpybuff(retour->msg,"OK");
  746.         guess_httptype(retour->contenttype,fil);
  747.       } else if (strnotempty(retour->msg)==0)
  748.           strcpybuff(retour->msg,"Unable to open local file");
  749.       return soc;  // renvoyer
  750.     } else {    // HEAD ou POST : interdit sur un local!!!! (c'est idiot!)
  751.       strcpybuff(retour->msg,"Unexpected Head/Post local request");
  752.       soc=INVALID_SOCKET;    // erreur
  753.       retour->soc=soc;
  754.       return soc;
  755.     }
  756.   } 
  757.   // --------------------
  758.  
  759.   if (soc!=INVALID_SOCKET) {    
  760.     char rcvd[1100];
  761.     rcvd[0]='\0';
  762. #if HDEBUG
  763.     printf("Ok, connexion rΘussie, id=%d\n",soc);
  764. #endif
  765.     
  766.     // connectΘ?
  767.     if (waitconnect) {
  768.       http_sendhead(NULL,mode,xsend,adr,fil,NULL,NULL,retour);
  769.     } 
  770.     
  771.     if (soc!=INVALID_SOCKET) {
  772.       
  773. #if HDEBUG
  774.       printf("Attente de la rΘponse:\n");
  775. #endif
  776.       
  777.       // si GET (rΘception d'un fichier), rΘceptionner en-tΩte d'abord,
  778.       // et ensuite le corps
  779.       // si POST on ne rΘceptionne rien du tout, c'est aprΦs que l'on fera
  780.       // une rΘception standard pour rΘcupΘrer l'en tΩte
  781.       if ((treat) && (waitconnect)) {  // traiter (attendre!) en-tΩte        
  782.         // RΘception de la status line et de l'en-tΩte (norme RFC1945)
  783.         
  784.         // status-line α rΘcupΘrer
  785.         finput(soc,rcvd,1024);
  786.         if (strnotempty(rcvd)==0)
  787.           finput(soc,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  788.  
  789.         // traiter status-line
  790.         treatfirstline(retour,rcvd);
  791.  
  792. #if HDEBUG
  793.         printf("Status-Code=%d\n",retour->statuscode);
  794. #endif
  795.         
  796.         // en-tΩte
  797.         
  798.         // header // ** !attention! HTTP/0.9 non supportΘ
  799.         do {
  800.           finput(soc,rcvd,1024);          
  801. #if HDEBUG
  802.           printf(">%s\n",rcvd);      
  803. #endif
  804.           if (strnotempty(rcvd))
  805.             treathead(NULL,NULL,NULL,retour,rcvd);  // traiter
  806.  
  807.         } while(strnotempty(rcvd));
  808.         
  809.         //rcvsize=-1;    // forCER CHARGEMENT INCONNU
  810.         
  811.         //if (retour)
  812.         //  retour->totalsize=rcvsize;
  813.         
  814.       } else { // si GET, on recevra l'en tΩte APRES
  815.         //rcvsize=-1;    // on ne connait pas la taille de l'en-tΩte
  816.         if (retour)
  817.           retour->totalsize=-1;
  818.       }
  819.       
  820.     }
  821.  
  822.   }
  823.     
  824.   return soc;
  825. }
  826.  
  827.  
  828. // envoi d'une requΦte
  829. int http_sendhead(t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char* referer_adr,char* referer_fil,htsblk* retour) {
  830.   char BIGSTK buff[8192];
  831.   //int use_11=0;     // HTTP 1.1 utilisΘ
  832.   int direct_url=0; // ne pas analyser l'url (exemple: ftp://)
  833.   char* search_tag=NULL;
  834.   buff[0]='\0';
  835.  
  836.   // header Date
  837.   //strcatbuff(buff,"Date: ");
  838.   //time_gmt_rfc822(buff);    // obtenir l'heure au format rfc822
  839.   //sendc("\n");
  840.   //strcatbuff(buff,buff);
  841.  
  842.   // possibilitΘ non documentΘe: >post: et >postfile:
  843.   // si prΘsence d'un tag >post: alors executer un POST
  844.   // exemple: http://www.someweb.com/test.cgi?foo>post:posteddata=10&foo=5
  845.   // si prΘsence d'un tag >postfile: alors envoyer en tΩte brut contenu dans le fichier en question
  846.   // exemple: http://www.someweb.com/test.cgi?foo>postfile:post0.txt
  847.   search_tag=strstr(fil,POSTTOK":");
  848.   if (!search_tag) {
  849.     search_tag=strstr(fil,POSTTOK"file:");
  850.     if (search_tag) {     // postfile
  851.       if (mode==0) {      // GET!
  852.         FILE* fp=fopen(unescape_http(search_tag+strlen(POSTTOK)+5),"rb");
  853.         if (fp) {
  854.           char BIGSTK line[1100];
  855.           char BIGSTK protocol[256],url[HTS_URLMAXSIZE*2],method[256];
  856.           linput(fp,line,1000);
  857.           if (sscanf(line,"%s %s %s",method,url,protocol) == 3) {
  858.             // selon que l'on a ou pas un proxy
  859.             if (retour->req.proxy.active)
  860.               sprintf(buff,"%s http://%s%s %s\r\n",method,adr,url,protocol);
  861.             else
  862.               sprintf(buff,"%s %s %s\r\n",method,url,protocol);
  863.             // lire le reste en brut
  864.             fread(buff+strlen(buff),8000-strlen(buff),1,fp);
  865.           }
  866.           fclose(fp);
  867.         }
  868.       }
  869.     }
  870.   }
  871.   // Fin postfile
  872.   
  873.   if (strnotempty(buff)==0) {    // PAS POSTFILE
  874.     // Type de requΦte?
  875.     if ((search_tag) && (mode==0)) {
  876.       strcatbuff(buff,"POST ");
  877.     } else if (mode==0) {    // GET
  878.       strcatbuff(buff,"GET ");
  879.     } else {  // if (mode==1) {
  880.       if (!retour->req.http11)        // forcer HTTP/1.0
  881.         strcatbuff(buff,"GET ");      // certains serveurs (cgi) buggent avec HEAD
  882.       else
  883.         strcatbuff(buff,"HEAD ");
  884.     }
  885.     
  886.     // si on gΦre un proxy, il faut une Absolute URI: on ajoute avant http://www.adr.dom
  887.     if ( retour->req.proxy.active && (strncmp(adr,"https://", 8) != 0) ) {
  888.       if (!link_has_authority(adr)) {  // default http
  889. #if HDEBUG
  890.         printf("Proxy Use: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  891. #endif
  892.         strcatbuff(buff,"http://");
  893.         strcatbuff(buff,jump_identification(adr));
  894.       } else {          // ftp:// en proxy http
  895. #if HDEBUG
  896.         printf("Proxy Use for ftp: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  897. #endif
  898.         direct_url=1;             // ne pas analyser user/pass
  899.         strcatbuff(buff,adr);
  900.       }
  901.     } 
  902.     
  903.     // NOM DU FICHIER
  904.     // on slash doit Ωtre prΘsent en dΘbut, sinon attention aux bad request! (400)
  905.     if (*fil!='/') strcatbuff(buff,"/");
  906.     {
  907.       char BIGSTK tempo[HTS_URLMAXSIZE*2];
  908.       tempo[0]='\0';
  909.       if (search_tag)
  910.         strncatbuff(tempo,fil,(int) (search_tag - fil));
  911.       else
  912.         strcpybuff(tempo,fil);
  913.       escape_check_url(tempo);
  914.       strcatbuff(buff,tempo);       // avec Θchappement
  915.     }
  916.     
  917.     // protocole
  918.     if (!retour->req.http11) {     // forcer HTTP/1.0
  919.       //use_11=0;
  920.       strcatbuff(buff," HTTP/1.0\x0d\x0a");
  921.     } else {                   // RequΦte 1.1
  922.       //use_11=1;
  923.       strcatbuff(buff," HTTP/1.1\x0d\x0a");
  924.     }
  925.  
  926.     /* supplemental data */
  927.     if (xsend) strcatbuff(buff,xsend);    // Θventuelles autres lignes
  928.  
  929.     // tester proxy authentication
  930.     if (retour->req.proxy.active) {
  931.       if (link_has_authorization(retour->req.proxy.name)) {  // et hop, authentification proxy!
  932.         char* a=jump_identification(retour->req.proxy.name);
  933.         char* astart=jump_protocol(retour->req.proxy.name);
  934.         char autorisation[1100];
  935.         char user_pass[256];        
  936.         autorisation[0]=user_pass[0]='\0';
  937.         //
  938.         strncatbuff(user_pass,astart,(int) (a - astart) - 1);
  939.         strcpybuff(user_pass,unescape_http(user_pass));
  940.         code64((unsigned char*)user_pass,(int)strlen(user_pass),(unsigned char*)autorisation,0);
  941.         strcatbuff(buff,"Proxy-Authorization: Basic ");
  942.         strcatbuff(buff,autorisation);
  943.         strcatbuff(buff,H_CRLF);
  944. #if HDEBUG
  945.         printf("Proxy-Authenticate, %s (code: %s)\n",user_pass,autorisation);
  946. #endif
  947.       }
  948.     }
  949.     
  950.     // Referer?
  951.     if (referer_adr != NULL && referer_fil != NULL 
  952.       && strnotempty(referer_adr) && strnotempty(referer_fil)
  953.       ) {   // non vide
  954.       if (
  955.         (strcmp(referer_adr,"file://") != 0)
  956.         &&
  957.         (  /* no https referer to http urls */
  958.         (strncmp(referer_adr, "https://", 8) != 0)  /* referer is not https */
  959.         ||
  960.         (strncmp(adr, "https://", 8) == 0)          /* or referer AND addresses are https */
  961.         )
  962.         ) {      // PAS file://
  963.         strcatbuff(buff,"Referer: ");
  964.         strcatbuff(buff,"http://");
  965.         strcatbuff(buff,jump_identification(referer_adr));
  966.         strcatbuff(buff,referer_fil);
  967.         strcatbuff(buff,H_CRLF);
  968.       }
  969.     }
  970.     // HTTP field: referer
  971.     else if (retour->req.referer[0] != '\0') {
  972.       strcatbuff(buff,"Referer: ");
  973.       strcatbuff(buff, retour->req.referer);
  974.       strcatbuff(buff, H_CRLF);     
  975.     }
  976.     
  977.     // POST?
  978.     if (mode==0) {      // GET!
  979.       if (search_tag) {
  980.         char clen[256];
  981.         sprintf(clen,"Content-length: %d"H_CRLF,(int)(strlen(unescape_http(search_tag+strlen(POSTTOK)+1))));
  982.         strcatbuff(buff,clen);
  983.       }
  984.     }
  985.     
  986.     // gestion cookies?
  987.     if (cookie) {
  988.       char* b=cookie->data;
  989.       int cook=0;
  990.       int max_cookies=8;
  991.       int max_size=2048;
  992.       max_size+=strlen(buff);
  993.       do {
  994.         b=cookie_find(b,"",jump_identification(adr),fil);       // prochain cookie satisfaisant aux conditions
  995.         if (b) {
  996.           max_cookies--;
  997.           if (!cook) {
  998.             strcatbuff(buff,"Cookie: ");
  999.             strcatbuff(buff,"$Version=1; ");
  1000.             cook=1;
  1001.           } else
  1002.             strcatbuff(buff,"; ");
  1003.           strcatbuff(buff,cookie_get(b,5));
  1004.           strcatbuff(buff,"=");
  1005.           strcatbuff(buff,cookie_get(b,6));
  1006.           strcatbuff(buff,"; $Path=");
  1007.           strcatbuff(buff,cookie_get(b,2));
  1008.           b=cookie_nextfield(b);
  1009.         }
  1010.       } while( (b) && (max_cookies>0) && ((int)strlen(buff)<max_size));
  1011.       if (cook) {                           // on a envoyΘ un (ou plusieurs) cookie?
  1012.         strcatbuff(buff,H_CRLF);
  1013. #if DEBUG_COOK
  1014.         printf("Header:\n%s\n",buff);
  1015. #endif
  1016.       }
  1017.     }
  1018.     
  1019.     // gΘrer le keep-alive (garder socket)
  1020.     if (retour->req.http11 && !retour->req.nokeepalive) {
  1021.             strcatbuff(buff,"Connection: Keep-Alive"H_CRLF);
  1022.         } else {
  1023.       strcatbuff(buff,"Connection: close"H_CRLF);
  1024.         }
  1025.     
  1026.     {
  1027.       char* real_adr=jump_identification(adr);
  1028.       //if ((use_11) || (retour->user_agent_send)) {   // Pour le 1.1 on utilise un Host:
  1029.       if (!direct_url) {     // pas ftp:// par exemple
  1030.         //if (!retour->req.proxy.active) {
  1031.         strcatbuff(buff,"Host: "); strcatbuff(buff,real_adr); strcatbuff(buff,H_CRLF);
  1032.         //}
  1033.       }
  1034.       //}
  1035.  
  1036.       // HTTP field: from
  1037.       if (retour->req.from[0] != '\0') {  // HTTP from
  1038.         strcatbuff(buff,"From: ");
  1039.         strcatbuff(buff, retour->req.from);
  1040.         strcatbuff(buff, H_CRLF);
  1041.       }
  1042.  
  1043.       // PrΘsence d'un user-agent?
  1044.       if (retour->req.user_agent_send) {  // ohh un user-agent
  1045.         char s[256];
  1046.         // HyperTextSeeker/"HTSVERSION
  1047.         sprintf(s,"User-Agent: %s"H_CRLF,retour->req.user_agent);
  1048.         strcatbuff(buff,s);
  1049.         
  1050.         // pour les serveurs difficiles
  1051.         strcatbuff(buff,"Accept: "
  1052.                         "image/png, image/jpeg, image/pjpeg, image/x-xbitmap, image/svg+xml"  /* Accepted */
  1053.                         ", "
  1054.                         "image/gif;q=0.9"  /* also accepted but with lower preference */
  1055.                         ", "
  1056.                         "*/*;q=0.1"        /* also accepted but with even lower preference */
  1057.                         H_CRLF);
  1058.         if (strnotempty(retour->req.lang_iso)) {
  1059.           strcatbuff(buff,"Accept-Language: "); strcatbuff(buff,retour->req.lang_iso); strcatbuff(buff,H_CRLF);
  1060.         }
  1061.         strcatbuff(buff,"Accept-Charset: "
  1062.                         "iso-8859-1"       /* we prefer ISO-8859-1 */
  1063.                         ", "
  1064.                         "iso-8859-*;q=0.9" /* or ISO-8859-* */
  1065.                         ", "
  1066.                         "utf-8;q=0.66"     /* UTF8 is also accepted */
  1067.                         ", "
  1068.                         "*;q=0.33"         /* and any other charset */
  1069.                         H_CRLF);   
  1070.         if (retour->req.http11) {
  1071. #if HTS_USEZLIB
  1072.           //strcatbuff(buff,"Accept-Encoding: gzip, deflate, compress, identity"H_CRLF);
  1073.           if (gz_is_available && (!retour->req.range_used) && (!retour->req.nocompression))
  1074.             strcatbuff(buff,"Accept-Encoding: "
  1075.                             "gzip"         /* gzip if the preffered encoding */
  1076.                             ", "
  1077.                             "identity;q=0.9"
  1078.                             H_CRLF);
  1079.           else
  1080.             strcatbuff(buff,"Accept-Encoding: identity"H_CRLF);       /* no compression */
  1081. #else
  1082.           strcatbuff(buff,"Accept-Encoding: identity"H_CRLF);         /* no compression */
  1083. #endif
  1084.         }
  1085.       } else {
  1086.         strcatbuff(buff,"Accept: */*"H_CRLF);         // le minimum
  1087.       }
  1088.  
  1089.       /* Authentification */
  1090.       {
  1091.         char autorisation[1100];
  1092.         char* a;
  1093.         autorisation[0]='\0';
  1094.         if (link_has_authorization(adr)) {  // ohh une authentification!
  1095.           char* a=jump_identification(adr);
  1096.           char* astart=jump_protocol(adr);
  1097.           if (!direct_url) {      // pas ftp:// par exemple
  1098.             char user_pass[256];
  1099.             user_pass[0]='\0';
  1100.             strncatbuff(user_pass,astart,(int) (a - astart) - 1);
  1101.             strcpybuff(user_pass,unescape_http(user_pass));
  1102.             code64((unsigned char*)user_pass,(int)strlen(user_pass),(unsigned char*)autorisation,0);
  1103.             if (strcmp(fil,"/robots.txt"))      /* pas robots.txt */
  1104.               bauth_add(cookie,astart,fil,autorisation);
  1105.           }
  1106.         } else if ( (a=bauth_check(cookie,real_adr,fil)) )
  1107.           strcpybuff(autorisation,a);
  1108.         /* On a une autorisation a donner?  */
  1109.         if (strnotempty(autorisation)) {
  1110.           strcatbuff(buff,"Authorization: Basic ");
  1111.           strcatbuff(buff,autorisation);
  1112.           strcatbuff(buff,H_CRLF);
  1113.         }
  1114.       }
  1115.  
  1116.     }
  1117.     //strcatbuff(buff,"Accept-Language: en\n");
  1118.     //strcatbuff(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
  1119.     
  1120.     // CRLF de fin d'en tΩte
  1121.     strcatbuff(buff,H_CRLF);
  1122.     
  1123.     // donnΘes complΘmentaires?
  1124.     if (search_tag)
  1125.     if (mode==0)      // GET!
  1126.       strcatbuff(buff,unescape_http(search_tag+strlen(POSTTOK)+1));
  1127.   }
  1128.   
  1129. #if HDEBUG
  1130. #endif
  1131.   if (_DEBUG_HEAD) {
  1132.     if (ioinfo) {
  1133.       fprintf(ioinfo,"[%d] request for %s%s:\r\n",retour->debugid,jump_identification(adr),fil);
  1134.       fprintfio(ioinfo,buff,"<<< ");
  1135.       fprintf(ioinfo,"\r\n");
  1136.       fflush(ioinfo);
  1137.     }
  1138.   }  // Fin test pas postfile
  1139.   //
  1140.  
  1141.   // Callback
  1142. #if HTS_ANALYSTE
  1143.   if (hts_htmlcheck_sendhead != NULL) {
  1144.     int test_head=hts_htmlcheck_sendhead(buff, adr, fil, referer_adr, referer_fil, retour);
  1145.     if (test_head!=1) {
  1146.       deletesoc_r(retour);
  1147.       strcpybuff(retour->msg,"Header refused by external wrapper");
  1148.       retour->soc=INVALID_SOCKET;
  1149.     }
  1150.   }
  1151. #endif
  1152.  
  1153.   // Envoi
  1154.   HTS_STAT.last_request = mtime_local();
  1155.   if (sendc(retour, buff)<0) {  // ERREUR, socket rompue?...
  1156.   //if (sendc(retour->soc,buff) != strlen(buff)) {  // ERREUR, socket rompue?...
  1157.     deletesoc_r(retour);  // fermer tout de mΩme
  1158.     // et tenter de reconnecter
  1159.     
  1160.     strcpybuff(retour->msg, "Write error");
  1161.     retour->soc=INVALID_SOCKET;
  1162.   }
  1163.   
  1164.   // RX'98
  1165.   return 0;
  1166. }
  1167.  
  1168.  
  1169.  
  1170.  
  1171. // traiter 1ere ligne d'en tΩte
  1172. void treatfirstline(htsblk* retour,char* rcvd) {
  1173.   char* a=rcvd;
  1174.   // exemple:
  1175.   // HTTP/1.0 200 OK
  1176.   if (*a) {
  1177.     // note: certains serveurs buggΘs renvoient HTTP/1.0\n200 OK ou " HTTP/1.0 200 OK"
  1178.     while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces au dΘbut
  1179.     if (strfield(a, "HTTP/")) {
  1180.       // sauter HTTP/1.x
  1181.       while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  1182.       if (*a != '\0') {
  1183.         while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  1184.         if ((*a>='0') && (*a<='9')) {
  1185.           sscanf(a,"%d",&(retour->statuscode));
  1186.           // sauter 200
  1187.           while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  1188.           while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  1189.           if ((strlen(a) > 1) && (strlen(a) < 64) )                // message retour
  1190.             strcpybuff(retour->msg,a);
  1191.           else
  1192.             infostatuscode(retour->msg,retour->statuscode);
  1193.           // type MIME par dΘfaut2
  1194.           strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1195.         } else {  // pas de code!
  1196.           retour->statuscode=STATUSCODE_INVALID;
  1197.           strcpybuff(retour->msg,"Unknown response structure");
  1198.         }
  1199.       } else {  // euhh??
  1200.         retour->statuscode=STATUSCODE_INVALID;
  1201.         strcpybuff(retour->msg,"Unknown response structure");
  1202.       }
  1203.     } else {
  1204.             if (*a == '<') {
  1205.         /* This is dirty .. */
  1206.         retour->statuscode=200;
  1207.         retour->keep_alive=0;
  1208.         strcpybuff(retour->msg, "Unknown, assuming junky server");
  1209.         strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1210.             } else if (strnotempty(a)) {
  1211.         retour->statuscode=STATUSCODE_INVALID;
  1212.         strcpybuff(retour->msg,"Unknown (not HTTP/xx) response structure");
  1213.       } else {
  1214.         /* This is dirty .. */
  1215.         retour->statuscode=200;
  1216.         retour->keep_alive=0;
  1217.         strcpybuff(retour->msg, "Unknown, assuming junky server");
  1218.         strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1219.       }
  1220.     }
  1221.   } else {  // vide!
  1222.     /*
  1223.     retour->statuscode=STATUSCODE_INVALID;
  1224.     strcpybuff(retour->msg,"Empty reponse or internal error");
  1225.     */
  1226.     /* This is dirty .. */
  1227.     retour->statuscode=200;
  1228.     strcpybuff(retour->msg, "Unknown, assuming junky server");
  1229.     strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1230.   }
  1231. }
  1232.  
  1233. // traiter ligne par ligne l'en tΩte
  1234. // gestion des cookies
  1235. void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) {
  1236.   int p;
  1237.   if ((p=strfield(rcvd,"Content-length:"))!=0) {
  1238. #if HDEBUG
  1239.     printf("ok, Content-length: dΘtectΘ\n");
  1240. #endif
  1241.     sscanf(rcvd+p,LLintP,&(retour->totalsize));
  1242.     if (retour->totalsize == 0) {
  1243.       retour->empty = 1;
  1244.     }
  1245.   }
  1246.   else if ((p=strfield(rcvd,"Content-Disposition:"))!=0) {
  1247.     while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1248.     if ((int) strlen(rcvd+p)<250) { // pas trop long?
  1249.       char tmp[256];
  1250.       char *a=NULL,*b=NULL;
  1251.       strcpybuff(tmp,rcvd+p);
  1252.       a=strstr(tmp,"filename=");
  1253.       if (a) {
  1254.         a+=strlen("filename=");
  1255.         while(is_space(*a)) a++;
  1256.         //a=strchr(a,'"');
  1257.         if (a) {
  1258.           char *c=NULL;
  1259.           //a++;      /* jump " */
  1260.           while((c=strchr(a,'/')))    /* skip all / (see RFC2616) */
  1261.             a=c+1;
  1262.           //b=strchr(a+1,'"');
  1263.           b=a+strlen(a)-1;
  1264.           while(is_space(*b)) b--;
  1265.           b++;
  1266.           if (b) {
  1267.             *b='\0';
  1268.             if ((int) strlen(a) < 200) { // pas trop long?
  1269.               strcpybuff(retour->cdispo,a);
  1270.             }
  1271.           }
  1272.         }
  1273.       } 
  1274.     }
  1275.   }
  1276.   else if ((p=strfield(rcvd,"Last-Modified:"))!=0) {
  1277.     while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1278.     if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1279.       //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1280.       strcpybuff(retour->lastmodified,rcvd+p);
  1281.     }
  1282.   }
  1283.   else if ((p=strfield(rcvd,"Date:"))!=0) {
  1284.     if (strnotempty(retour->lastmodified)==0) {          /* pas encore de last-modified */
  1285.       while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1286.       if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1287.         //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1288.         strcpybuff(retour->lastmodified,rcvd+p);
  1289.       }
  1290.     }
  1291.   }
  1292.   else if ((p=strfield(rcvd,"Etag:"))!=0) {   /* Etag */
  1293.     if (retour) {
  1294.       while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1295.       if ((int) strlen(rcvd+p)<64)  // pas trop long?
  1296.         strcpybuff(retour->etag,rcvd+p);
  1297.       else    // erreur.. ignorer
  1298.         retour->etag[0]='\0';
  1299.     }
  1300.   }
  1301.   // else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) {  // chunk!
  1302.   else if ((p=strfield(rcvd,"Transfer-Encoding:"))!=0) {  // chunk!
  1303.     while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1304.     if (strfield(rcvd+p,"chunked")) {
  1305.       retour->is_chunk=1;     // chunked
  1306.       //retour->http11=2;     // chunked
  1307. #if HDEBUG
  1308.       printf("ok, Transfer-Encoding: dΘtectΘ\n");
  1309. #endif
  1310.     }
  1311.   }
  1312.   else if ((p=strfield(rcvd,"Content-type:"))!=0) {
  1313.     if (retour) {
  1314.       char tempo[1100];
  1315.       // Θviter les text/html; charset=foo
  1316.       {
  1317.         char* a=strchr(rcvd+p,';');
  1318.         if (a) {   // extended information
  1319.           *a='\0';
  1320.           a++;
  1321.               while(is_space(*a)) a++;
  1322.           if (strfield(a, "charset")) {
  1323.             a += 7;
  1324.                 while(is_space(*a)) a++;
  1325.             if (*a == '=') {
  1326.               a++;
  1327.                   while(is_space(*a)) a++;
  1328.               if (*a == '\"') a++;
  1329.                   while(is_space(*a)) a++;
  1330.               if (*a) {
  1331.                 char* chs = a;
  1332.                 while(*a && !is_space(*a) && *a != '\"' && *a != ';') a++;
  1333.                 *a = '\0';
  1334.                 if (*chs) {
  1335.                   if (strlen(chs) < sizeof(retour->charset) - 2) {
  1336.                     strcpybuff(retour->charset, chs);
  1337.                   }
  1338.                 }
  1339.               }
  1340.             }
  1341.           }
  1342.         }
  1343.       }
  1344.       sscanf(rcvd+p,"%s",tempo);
  1345.       if (strlen(tempo) < sizeof(retour->contenttype) - 2)    // pas trop long!!
  1346.         strcpybuff(retour->contenttype,tempo);
  1347.       else
  1348.         strcpybuff(retour->contenttype,"application/octet-stream-unknown");    // erreur
  1349.     }
  1350.   }
  1351.   else if ((p=strfield(rcvd,"Content-Range:"))!=0) {
  1352.     char* a=strstr(rcvd+p,"*/");
  1353.     if (a) {
  1354.       if (sscanf(a+2,LLintP,&retour->crange) != 1) {
  1355.         retour->crange=0;
  1356.       }
  1357.     }
  1358.   }
  1359.   else if ((p=strfield(rcvd,"Connection:"))!=0) {
  1360.         char* a = rcvd + p;
  1361.         while(is_space(*a)) a++;
  1362.         if (*a) {
  1363.             if (strfield(a, "Keep-Alive")) {
  1364.         if (!retour->keep_alive) {
  1365.           retour->keep_alive_max = 10;
  1366.           retour->keep_alive_t = 15;
  1367.         }
  1368.         retour->keep_alive = 1;
  1369.       } else {
  1370.                 retour->keep_alive = 0;
  1371.       }
  1372.         }
  1373.     }
  1374.   else if ((p=strfield(rcvd,"Keep-Alive:"))!=0) {
  1375.         char* a = rcvd + p;
  1376.         while(is_space(*a)) a++;
  1377.         if (*a) {
  1378.       char* p;
  1379.       retour->keep_alive = 1;
  1380.       retour->keep_alive_max = 10;
  1381.       retour->keep_alive_t = 15;
  1382.       if ((p=strstr(a, "timeout="))) {
  1383.         p+=strlen("timeout=");
  1384.         sscanf(p, "%d", &retour->keep_alive_t);
  1385.       }
  1386.       if ((p=strstr(a, "max="))) {
  1387.         p+=strlen("max=");
  1388.         sscanf(p, "%d", &retour->keep_alive_max);
  1389.       }
  1390.       if (retour->keep_alive_max <= 1 || retour->keep_alive_t < 3) {
  1391.         retour->keep_alive = 0;
  1392.       }
  1393.     }
  1394.   }
  1395.   else if ((p=strfield(rcvd,"TE:"))!=0) {
  1396.         char* a = rcvd + p;
  1397.         while(is_space(*a)) a++;
  1398.         if (*a) {
  1399.       if (strfield(a, "trailers")) {
  1400.         retour->keep_alive_trailers=1;
  1401.       }
  1402.     }
  1403.   }
  1404.     else if ((p=strfield(rcvd,"Content-Encoding:"))!=0) {
  1405.         if (retour) {
  1406.             char tempo[1100];
  1407.       char* a = rcvd + p;
  1408.       while(is_space(*a)) a++;
  1409.             {
  1410.                 char* a=strchr(rcvd+p,';');
  1411.                 if (a) *a='\0';
  1412.             }
  1413.             sscanf(a,"%s",tempo);
  1414.       if (strlen(tempo)<64)    // pas trop long!!
  1415.         strcpybuff(retour->contentencoding,tempo);
  1416.       else
  1417.         retour->contentencoding[0]='\0';    // erreur
  1418. #if HTS_USEZLIB
  1419.       /* Check known encodings */
  1420.       if (retour->contentencoding[0]) {
  1421.         if (
  1422.           (strfield2(retour->contentencoding, "gzip"))
  1423.           || (strfield2(retour->contentencoding, "x-gzip"))
  1424.           /*
  1425.           || (strfield2(retour->contentencoding, "compress"))
  1426.           || (strfield2(retour->contentencoding, "x-compress"))
  1427.           */
  1428.           || (strfield2(retour->contentencoding, "deflate"))
  1429.           || (strfield2(retour->contentencoding, "x-deflate"))
  1430.           ) {
  1431.         retour->compressed=1;
  1432.         }
  1433.       }
  1434. #endif
  1435.     }
  1436.   }
  1437.   else if ((p=strfield(rcvd,"Location:"))!=0) {
  1438.     if (retour) {
  1439.       if (retour->location) {
  1440.         while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1441.         if ((int) strlen(rcvd+p)<HTS_URLMAXSIZE)  // pas trop long?
  1442.           strcpybuff(retour->location,rcvd+p);
  1443.         else    // erreur.. ignorer
  1444.           retour->location[0]='\0';
  1445.       }
  1446.     }
  1447.   }
  1448.   else if ( ((p=strfield(rcvd,"Set-Cookie:"))!=0) && (cookie) ) {    // ohh un cookie
  1449.     char* a = rcvd+p;           // pointeur
  1450.     char domain[256];           // domaine cookie (.netscape.com)
  1451.     char path[256];             // chemin (/)
  1452.     char cook_name[256];        // nom cookie (MYCOOK)
  1453.     char BIGSTK cook_value[8192];      // valeur (ID=toto,S=1234)
  1454. #if DEBUG_COOK
  1455.     printf("set-cookie detected\n");
  1456. #endif
  1457.     while(*a) {
  1458.       char *token_st,*token_end;
  1459.       char *value_st,*value_end;
  1460.       char name[256];
  1461.       char BIGSTK value[8192];
  1462.       int next=0;
  1463.       name[0]=value[0]='\0';
  1464.       //
  1465.  
  1466.       // initialiser cookie lu actuellement
  1467.       if (adr)
  1468.         strcpybuff(domain,jump_identification(adr));     // domaine
  1469.       strcpybuff(path,"/");         // chemin (/)
  1470.       strcpybuff(cook_name,"");     // nom cookie (MYCOOK)
  1471.       strcpybuff(cook_value,"");    // valeur (ID=toto,S=1234)
  1472.       // boucler jusqu'au prochain cookie ou la fin
  1473.       do {
  1474.         char* start_loop=a;
  1475.         while(is_space(*a)) a++;    // sauter espaces
  1476.         token_st=a;                 // dΘpart token
  1477.         while((!is_space(*a)) && (*a) && (*a!=';') && (*a!='=')) a++;    // arrΩter si espace, point virgule
  1478.         token_end=a;
  1479.         while(is_space(*a)) a++;    // sauter espaces
  1480.         if (*a=='=') {    // name=value
  1481.           a++;
  1482.           while(is_space(*a)) a++;    // sauter espaces
  1483.           value_st=a;
  1484.           while( (*a!=';') && (*a)) a++;    // prochain ;
  1485.           //while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++;    // prochain " (et pas \")
  1486.           value_end=a;
  1487.           //if (*a==';') {  // finit par un ;
  1488.           // vΘrifier dΘbordements
  1489.           if ( (((int) (token_end - token_st))<200) && (((int) (value_end - value_st))<8000)
  1490.             && (((int) (token_end - token_st))>0)   && (((int) (value_end - value_st))>0) ) 
  1491.           {
  1492.             int name_len = (int) (token_end - token_st);
  1493.             int value_len = (int) (value_end - value_st);
  1494.             name[0]='\0';
  1495.             value[0]='\0';
  1496.             strncatbuff(name,token_st,name_len);
  1497.             strncatbuff(value,value_st,value_len);
  1498. #if DEBUG_COOK
  1499.             printf("detected cookie-av: name=\"%s\" value=\"%s\"\n",name,value);
  1500. #endif
  1501.             if (strfield2(name,"domain")) {
  1502.               if (value_len < sizeof(domain) - 1) {
  1503.                 strcpybuff(domain,value);
  1504.               } else {
  1505.                 cook_name[0] = 0;
  1506.                 break;
  1507.               }
  1508.             }
  1509.             else if (strfield2(name,"path")) {
  1510.               if (value_len < sizeof(path) - 1) {
  1511.                 strcpybuff(path,value);
  1512.               } else {
  1513.                 cook_name[0] = 0;
  1514.                 break;
  1515.               }
  1516.             }
  1517.             else if (strfield2(name,"max-age")) {
  1518.               // ignorΘ..
  1519.             }
  1520.             else if (strfield2(name,"expires")) {
  1521.               // ignorΘ..
  1522.             }
  1523.             else if (strfield2(name,"version")) {
  1524.               // ignorΘ..
  1525.             }
  1526.             else if (strfield2(name,"comment")) {
  1527.               // ignorΘ
  1528.             }
  1529.             else if (strfield2(name,"secure")) {    // ne devrait pas arriver ici
  1530.               // ignorΘ
  1531.             }
  1532.             else {
  1533.               if (value_len < sizeof(cook_value) - 1 && name_len < sizeof(cook_name) - 1) {
  1534.                 if (strnotempty(cook_name)==0) {          // noter premier: nom et valeur cookie
  1535.                   strcpybuff(cook_name,name);
  1536.                   strcpybuff(cook_value,value);
  1537.                 } else {                             // prochain cookie
  1538.                   a=start_loop;      // on devra recommencer α cette position
  1539.                   next=1;            // enregistrer
  1540.                 }
  1541.               } else {
  1542.                 cook_name[0] = 0;
  1543.                 break;
  1544.               }
  1545.             }
  1546.           }
  1547.         }
  1548.         if (!next) {
  1549.           while((*a!=';') && (*a)) a++;    // prochain
  1550.           while(*a==';') a++;             // sauter ;
  1551.         }
  1552.       } while((*a) && (!next));
  1553.       if (strnotempty(cook_name)) {          // cookie?
  1554. #if DEBUG_COOK
  1555.         printf("new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",cook_name,cook_value,domain,path);
  1556. #endif
  1557.         cookie_add(cookie,cook_name,cook_value,domain,path);
  1558.       }
  1559.     }
  1560.   }
  1561. }
  1562.  
  1563.  
  1564. // transforme le message statuscode en chaεne
  1565. HTSEXT_API void infostatuscode(char* msg,int statuscode) {
  1566.   switch( statuscode) {    
  1567.     // Erreurs HTTP, selon RFC
  1568.   case 100: strcpybuff( msg,"Continue"); break; 
  1569.   case 101: strcpybuff( msg,"Switching Protocols"); break; 
  1570.   case 200: strcpybuff( msg,"OK"); break; 
  1571.   case 201: strcpybuff( msg,"Created"); break; 
  1572.   case 202: strcpybuff( msg,"Accepted"); break; 
  1573.   case 203: strcpybuff( msg,"Non-Authoritative Information"); break; 
  1574.   case 204: strcpybuff( msg,"No Content"); break; 
  1575.   case 205: strcpybuff( msg,"Reset Content"); break; 
  1576.   case 206: strcpybuff( msg,"Partial Content"); break; 
  1577.   case 300: strcpybuff( msg,"Multiple Choices"); break; 
  1578.   case 301: strcpybuff( msg,"Moved Permanently"); break; 
  1579.   case 302: strcpybuff( msg,"Moved Temporarily"); break; 
  1580.   case 303: strcpybuff( msg,"See Other"); break; 
  1581.   case 304: strcpybuff( msg,"Not Modified"); break; 
  1582.   case 305: strcpybuff( msg,"Use Proxy"); break; 
  1583.   case 306: strcpybuff( msg,"Undefined 306 error"); break; 
  1584.   case 307: strcpybuff( msg,"Temporary Redirect"); break; 
  1585.   case 400: strcpybuff( msg,"Bad Request"); break; 
  1586.   case 401: strcpybuff( msg,"Unauthorized"); break; 
  1587.   case 402: strcpybuff( msg,"Payment Required"); break; 
  1588.   case 403: strcpybuff( msg,"Forbidden"); break; 
  1589.   case 404: strcpybuff( msg,"Not Found"); break; 
  1590.   case 405: strcpybuff( msg,"Method Not Allowed"); break; 
  1591.   case 406: strcpybuff( msg,"Not Acceptable"); break; 
  1592.   case 407: strcpybuff( msg,"Proxy Authentication Required"); break; 
  1593.   case 408: strcpybuff( msg,"Request Time-out"); break; 
  1594.   case 409: strcpybuff( msg,"Conflict"); break; 
  1595.   case 410: strcpybuff( msg,"Gone"); break; 
  1596.   case 411: strcpybuff( msg,"Length Required"); break; 
  1597.   case 412: strcpybuff( msg,"Precondition Failed"); break; 
  1598.   case 413: strcpybuff( msg,"Request Entity Too Large"); break; 
  1599.   case 414: strcpybuff( msg,"Request-URI Too Large"); break; 
  1600.   case 415: strcpybuff( msg,"Unsupported Media Type"); break; 
  1601.   case 416: strcpybuff( msg,"Requested Range Not Satisfiable"); break; 
  1602.   case 417: strcpybuff( msg,"Expectation Failed"); break; 
  1603.   case 500: strcpybuff( msg,"Internal Server Error"); break; 
  1604.   case 501: strcpybuff( msg,"Not Implemented"); break; 
  1605.   case 502: strcpybuff( msg,"Bad Gateway"); break; 
  1606.   case 503: strcpybuff( msg,"Service Unavailable"); break; 
  1607.   case 504: strcpybuff( msg,"Gateway Time-out"); break; 
  1608.   case 505: strcpybuff( msg,"HTTP Version Not Supported"); break; 
  1609.     //
  1610.   default: if (strnotempty(msg)==0) strcpybuff( msg,"Unknown error"); break;
  1611.   }
  1612. }
  1613.  
  1614.  
  1615. // identique au prΘcΘdent, sauf que l'on donne adr+fil et non url complΦte
  1616. htsblk xhttpget(char* adr,char* fil) {
  1617.   T_SOC soc;
  1618.   htsblk retour;
  1619.   
  1620.   memset(&retour, 0, sizeof(htsblk));
  1621.   soc=http_fopen(adr,fil,&retour);
  1622.  
  1623.   if (soc!=INVALID_SOCKET) {
  1624.     http_fread(soc,&retour);
  1625. #if HTS_DEBUG_CLOSESOCK
  1626.     DEBUG_W("xhttpget: deletehttp\n");
  1627. #endif
  1628.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1629.     retour.soc=INVALID_SOCKET;
  1630.   }
  1631.   return retour;
  1632. }
  1633.  
  1634. // variation sur un thΦme...
  1635. // rΘceptionne uniquement un en-tΩte (HEAD)
  1636. // retourne dans xx.adr l'adresse pointant sur le bloc de mΘmoire de l'en tΩte
  1637. htsblk http_gethead(char* adr,char* fil) {
  1638.   T_SOC soc;
  1639.   htsblk retour;
  1640.  
  1641.   memset(&retour, 0, sizeof(htsblk));
  1642.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // HEAD, pas de traitement en-tΩte
  1643.  
  1644.   if (soc!=INVALID_SOCKET) {
  1645.     http_fread(soc,&retour);    // rΘception en-tΩte
  1646. #if HTS_DEBUG_CLOSESOCK
  1647.     DEBUG_W("http_gethead: deletehttp\n");
  1648. #endif
  1649.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1650.     retour.soc=INVALID_SOCKET;
  1651.   }
  1652.   return retour;
  1653. }
  1654. // oui ca ressemble vachement α xhttpget - en Θtant sobre on peut voir LA diffΘrence..
  1655.  
  1656.  
  1657. // lecture sur une socket ouverte, le header a dΘja ΘtΘ envoyΘ dans le cas de GET
  1658. // il ne reste plus qu'α lire les donnΘes
  1659. // (pour HEAD le header est lu ici!)
  1660. void http_fread(T_SOC soc,htsblk* retour) {  
  1661.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1662.   
  1663.   if (retour) retour->soc=soc;
  1664.   if (soc!=INVALID_SOCKET) {    
  1665.     // fonction de lecture d'une socket (plus propre)
  1666.     while(http_fread1(retour)!=-1);
  1667.     soc=retour->soc;
  1668.     if (retour->adr==NULL) {
  1669.       if (strnotempty(retour->msg)==0)
  1670.         sprintf(retour->msg,"Unable to read");
  1671.       return ;    // erreur
  1672.     } 
  1673.     
  1674. #if HDEBUG
  1675.     printf("Ok, donnΘes reτues\n");
  1676. #endif   
  1677.  
  1678.     return ;
  1679.     
  1680.   } 
  1681.   
  1682.   return ;
  1683. }
  1684.  
  1685. // check if data is available
  1686. int check_readinput(htsblk* r) {
  1687.   if (r->soc != INVALID_SOCKET) {
  1688.     fd_set fds;           // poll structures
  1689.     struct timeval tv;          // structure for select
  1690.     FD_ZERO(&fds);
  1691.     FD_SET(r->soc,&fds);           
  1692.     tv.tv_sec=0;
  1693.     tv.tv_usec=0;
  1694.     select(r->soc + 1,&fds,NULL,NULL,&tv);
  1695.     if (FD_ISSET(r->soc,&fds))
  1696.       return 1;
  1697.     else
  1698.       return 0;
  1699.   } else
  1700.     return 0;
  1701. }
  1702.  
  1703. // check if data is available
  1704. int check_readinput_t(T_SOC soc, int timeout) {
  1705.   if (soc != INVALID_SOCKET) {
  1706.     fd_set fds;           // poll structures
  1707.     struct timeval tv;          // structure for select
  1708.     FD_ZERO(&fds);
  1709.     FD_SET(soc,&fds);           
  1710.     tv.tv_sec=timeout;
  1711.     tv.tv_usec=0;
  1712.     select(soc + 1,&fds,NULL,NULL,&tv);
  1713.     if (FD_ISSET(soc,&fds))
  1714.       return 1;
  1715.     else
  1716.       return 0;
  1717.   } else
  1718.     return 0;
  1719. }
  1720.  
  1721.  
  1722. // lecture d'un bloc sur une socket (ou un fichier!)
  1723. // >=0 : nombre d'octets lus
  1724. // <0 : fin ou erreur
  1725. HTS_INLINE LLint http_fread1(htsblk* r) {
  1726.   //int bufl=TAILLE_BUFFER;  // taille d'un buffer max.
  1727.   return http_xfread1(r,TAILLE_BUFFER);
  1728. }
  1729.  
  1730. // idem, sauf qu'ici on peut choisir la taille max de donnΘes α recevoir
  1731. // SI bufl==0 alors le buffer est censΘ Ωtre de 8kos, et on recoit par bloc de lignes
  1732. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1733. // SI bufl==-1 alors le buffer est censΘ Ωtre de 8kos, et on recoit ligne par ligne
  1734. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1735. // Note: les +1 dans les malloc sont d√s α l'octet nul rajoutΘ en fin de fichier
  1736. LLint http_xfread1(htsblk* r,int bufl) {
  1737.   int nl=-1;
  1738.  
  1739.   // EOF
  1740.   if (r->totalsize > 0 && r->size == r->totalsize) {
  1741.     return READ_EOF;
  1742.   }
  1743.  
  1744.   if (bufl>0) {
  1745.     if (!r->is_write) {     // stocker en mΘmoire
  1746.       if (r->totalsize>0) {    // totalsize dΘterminΘ ET ALLOUE
  1747.         if (r->adr==NULL) {
  1748.           r->adr=(char*) malloct((INTsys) r->totalsize + 1);
  1749.           r->size=0;
  1750.         }
  1751.         if (r->adr!=NULL) {
  1752.           // lecture
  1753.           nl = hts_read(r,r->adr + ((int) r->size),(int) (r->totalsize-r->size) );     /* NO 32 bit overlow possible here (no 4GB html!) */
  1754.           // nouvelle taille
  1755.           if (nl >= 0) r->size+=nl;
  1756.  
  1757.           /*
  1758.           if (r->size >= r->totalsize)
  1759.             nl = -1;  // break
  1760.           */
  1761.           
  1762.           r->adr[r->size]='\0';    // caractΦre NULL en fin au cas o∙ l'on traite des HTML
  1763.         }
  1764.         
  1765.       } else {                 // inconnu..
  1766.         // rΘserver de la mΘmoire?
  1767.         if (r->adr==NULL) {
  1768. #if HDEBUG
  1769.           printf("..alloc xfread\n");
  1770. #endif
  1771.           r->adr=(char*) malloct(bufl + 1);
  1772.           r->size=0;
  1773.         }
  1774.         else {
  1775. #if HDEBUG
  1776.           printf("..realloc xfread1\n");
  1777. #endif
  1778.           r->adr=(char*) realloct(r->adr,(int)r->size+bufl + 1);
  1779.         }
  1780.         
  1781.         if (r->adr!=NULL) {
  1782.           // lecture
  1783.           nl = hts_read(r,r->adr+(int)r->size,bufl);
  1784.           if (nl > 0) {
  1785.             // resize
  1786.             r->adr=(char*) realloct(r->adr,(int)r->size+nl + 1);
  1787.             // nouvelle taille
  1788.             r->size+=nl;
  1789.             // octet nul
  1790.             if (r->adr) r->adr[r->size]='\0';
  1791.  
  1792.           } // sinon on a fini
  1793. #if HDEBUG
  1794.           else if (nl < 0)
  1795.             printf("..end read (%d)\n", nl);
  1796. #endif
  1797.         }
  1798. #if HDEBUG
  1799.         else printf("..-> error\n");
  1800. #endif
  1801.       }
  1802.  
  1803.       // pas de adr=erreur
  1804.       if (r->adr == NULL) nl = READ_ERROR;
  1805.  
  1806.     } else {    // stocker sur disque
  1807.       char* buff;
  1808.       buff=(char*) malloct(bufl);
  1809.       if (buff!=NULL) {
  1810.         // lecture
  1811.         nl = hts_read(r,buff,bufl);
  1812.         // nouvelle taille
  1813.         if (nl > 0) { 
  1814.           r->size+=nl;
  1815.           if ((INTsys)fwrite(buff,1,nl,r->out)!=nl) {
  1816.             r->statuscode=STATUSCODE_INVALID;
  1817.             strcpybuff(r->msg,"Write error on disk");
  1818.             nl=READ_ERROR;
  1819.           }
  1820.         }
  1821.  
  1822.         //if ((nl < 0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
  1823.         //  nl=-1;  // break
  1824.  
  1825.         // libΘrer bloc tempo
  1826.         freet(buff);
  1827.       } else
  1828.         nl=READ_ERROR;
  1829.       
  1830.       if ((nl < 0) && (r->out!=NULL)) {
  1831.         fflush(r->out); 
  1832.       }
  1833.         
  1834.         
  1835.     } // stockage disque ou mΘmoire
  1836.  
  1837.   } else if (bufl == -2) {  // force reserve
  1838.     if (r->adr==NULL) {
  1839.       r->adr=(char*) malloct(8192);
  1840.       r->size=0;
  1841.       return 0;
  1842.     }
  1843.     return -1;
  1844.   } else {    // rΘception d'un en-tΩte octet par octet
  1845.     int count=256;
  1846.     int tot_nl=0;
  1847.     int lf_detected=0;
  1848.     int at_begining=1;
  1849.     do {
  1850.       nl = READ_INTERNAL_ERROR;
  1851.       count--;
  1852.       if (r->adr==NULL) {
  1853.         r->adr=(char*) malloct(8192);
  1854.         r->size=0;
  1855.       }
  1856.       if (r->adr!=NULL) {
  1857.         if (r->size < 8190) {
  1858.           // lecture
  1859.           nl = hts_read(r,r->adr+r->size,1);
  1860.           if (nl > 0) {
  1861.             // exit if:
  1862.             // lf detected AND already detected before
  1863.             // or
  1864.             // lf detected AND first character read
  1865.             if (*(r->adr+r->size) == 10) {
  1866.               if (lf_detected || (at_begining) || (bufl<0))
  1867.                 count=-1;
  1868.               lf_detected=1;
  1869.             }
  1870.             if (*(r->adr+r->size) != 13) {   // sauter caractΦres 13
  1871.               if (
  1872.                 (*(r->adr+r->size) != 10)
  1873.                 &&
  1874.                 (*(r->adr+r->size) != 13)
  1875.                 ) {
  1876.                 // restart for new line
  1877.                 lf_detected=0;
  1878.               }
  1879.               (r->size)++;
  1880.               at_begining=0;
  1881.             }
  1882.             *(r->adr+r->size)='\0';    // terminer par octet nul
  1883.           }
  1884.         }
  1885.       }
  1886.       if (nl >= 0) {
  1887.         tot_nl+=nl;
  1888.         if (!check_readinput(r))
  1889.           count=-1;
  1890.       }
  1891.     } while((nl >= 0) && (count>0));
  1892.     if (nl >= 0) {
  1893.       nl = tot_nl;
  1894.     }
  1895.   }
  1896.   // EOF
  1897.   if (r->totalsize > 0 && r->size == r->totalsize) {
  1898.     return READ_EOF;
  1899.   } else {
  1900.     return nl;
  1901.   }
  1902. }
  1903.  
  1904.  
  1905. // teste une adresse, et suit l'Θventuel chemin "moved"
  1906. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1907. // copie dans loc la vΘritable adresse si celle-ci est diffΘrente
  1908. htsblk http_location(char* adr,char* fil,char* loc) {
  1909.   htsblk retour;
  1910.   int retry=0;
  1911.   int tryagain;
  1912.   // note: "RFC says"
  1913.   // 5 boucles au plus, on en teste au plus 8 ici
  1914.   // sinon abandon..
  1915.   do {
  1916.     tryagain=0;
  1917.     switch ((retour=http_test(adr,fil,loc)).statuscode) {
  1918.     case 200: break;   // ok!
  1919.     case 301: case 302: case 303: case 307: // moved!
  1920.       // recalculer adr et fil!
  1921.       if (ident_url_absolute(loc,adr,fil)!=-1) {
  1922.         tryagain=1;  // retenter
  1923.         retry++;     // ..encore une fois
  1924.       }
  1925.     }
  1926.   } while((tryagain) && (retry<5+3));
  1927.   return retour;
  1928. }
  1929.  
  1930.  
  1931. // teste si une URL (validitΘ, header, taille)
  1932. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1933. // en cas de moved xx, dans location
  1934. // abandonne dΘsormais au bout de 30 secondes (aurevoir les sites
  1935. // qui nous font poireauter 5 heures..) -> -2=timeout
  1936. htsblk http_test(char* adr,char* fil,char* loc) {
  1937.   T_SOC soc;
  1938.   htsblk retour;
  1939.   //int rcvsize=-1;
  1940.   //char* rcv=NULL;    // adresse de retour
  1941.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1942.   TStamp tl;
  1943.   int timeout=30;  // timeout pour un check (arbitraire) // **
  1944.  
  1945.   // pour abandonner un site trop lent
  1946.   tl=time_local();
  1947.  
  1948.   loc[0]='\0';
  1949.   memset(&retour, 0, sizeof(htsblk));    // effacer
  1950.   retour.location=loc;    // si non nul, contiendra l'adresse vΘritable en cas de moved xx
  1951.  
  1952.   //soc=http_fopen(adr,fil,&retour,NULL);  // ouvrir, + header
  1953.  
  1954.   // on ouvre en head, et on traite l'en tΩte
  1955.   soc=http_xfopen(1,0,1,NULL,adr,fil,&retour);  // ouvrir HEAD, + envoi header
  1956.   
  1957.   if (soc!=INVALID_SOCKET) {
  1958.     int e=0;
  1959.     // tant qu'on a des donnΘes, et qu'on ne recoit pas deux LF, et que le timeout n'arrie pas
  1960.     do {
  1961.       if (http_xfread1(&retour,0) < 0)
  1962.         e=1;
  1963.       else {
  1964.         if (retour.adr!=NULL) {
  1965.           if ((retour.adr[retour.size-1]!=10) || (retour.adr[retour.size-2]!=10))
  1966.             e=1;
  1967.         }
  1968.       }
  1969.             
  1970.       if (!e) {
  1971.         if ((time_local()-tl)>=timeout) {
  1972.           e=-1;
  1973.         }
  1974.       }
  1975.       
  1976.     } while (!e);
  1977.     
  1978.     if (e==1) {
  1979.       if (adr!=NULL) {
  1980.         int ptr=0;
  1981.         char rcvd[1100];
  1982.  
  1983.         // note: en gros recopie du traitement de back_wait()
  1984.         //
  1985.  
  1986.  
  1987.         // ----------------------------------------
  1988.         // traiter en-tΩte!
  1989.         // status-line α rΘcupΘrer
  1990.         ptr+=binput(retour.adr+ptr,rcvd,1024);
  1991.         if (strnotempty(rcvd)==0)
  1992.           ptr+=binput(retour.adr+ptr,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  1993.         
  1994.         // traiter status-line
  1995.         treatfirstline(&retour,rcvd);
  1996.         
  1997. #if HDEBUG
  1998.         printf("(Buffer) Status-Code=%d\n",retour.statuscode);
  1999. #endif
  2000.         
  2001.         // en-tΩte
  2002.         
  2003.         // header // ** !attention! HTTP/0.9 non supportΘ
  2004.         do {
  2005.           ptr+=binput(retour.adr+ptr,rcvd,1024);          
  2006. #if HDEBUG
  2007.           printf("(buffer)>%s\n",rcvd);      
  2008. #endif
  2009.           if (strnotempty(rcvd))
  2010.             treathead(NULL,NULL,NULL,&retour,rcvd);  // traiter
  2011.           
  2012.         } while(strnotempty(rcvd));
  2013.         // ----------------------------------------                    
  2014.         
  2015.         // libΘrer mΘmoire
  2016.         if (retour.adr!=NULL) { freet(retour.adr); retour.adr=NULL; }
  2017.       }
  2018.     } else {
  2019.       retour.statuscode=STATUSCODE_TIMEOUT;
  2020.       strcpybuff(retour.msg,"Timeout While Testing");
  2021.     }
  2022.     
  2023.     
  2024. #if HTS_DEBUG_CLOSESOCK
  2025.     DEBUG_W("http_test: deletehttp\n");
  2026. #endif
  2027.     deletehttp(&retour);
  2028.     retour.soc=INVALID_SOCKET;
  2029.   }
  2030.   return retour;    
  2031. }
  2032.  
  2033. // CrΘe un lien (http) vers une adresse internet iadr
  2034. // retour: structure (adresse, taille, message si erreur (si !adr))
  2035. // peut ouvrir avec des connect() non bloquants: waitconnect=0/1
  2036. int newhttp(char* _iadr,htsblk* retour,int port,int waitconnect) {  
  2037.   t_fullhostent fullhostent_buffer;    // buffer pour resolver
  2038.   T_SOC soc;                           // descipteur de la socket
  2039.   char* iadr;
  2040.   // unsigned short int port;
  2041.   
  2042.   // si iadr="#" alors c'est une fausse URL, mais un vrai fichier
  2043.   // local.
  2044.   // utile pour les tests!
  2045.   //## if (iadr[0]!=lOCAL_CHAR) {
  2046.   if (strcmp(_iadr,"file://") != 0) {           /* non fichier */
  2047.     SOCaddr server;
  2048.     int server_size=sizeof(server);
  2049.     t_hostent* hp;    
  2050.     // effacer structure
  2051.     memset(&server, 0, sizeof(server));
  2052.  
  2053.     // tester un Θventuel id:pass et virer id:pass@ si dΘtectΘ
  2054.     iadr = jump_identification(_iadr);
  2055.   
  2056. #if HDEBUG
  2057.     printf("gethostbyname\n");
  2058. #endif
  2059.     
  2060.     // tester un Θventuel port
  2061.     if (port==-1) {
  2062.       char *a=jump_toport(iadr);
  2063. #if HTS_USEOPENSSL
  2064.       if (retour->ssl)
  2065.         port=443;
  2066.       else
  2067.         port=80;    // port par dΘfaut
  2068. #else
  2069.       port=80;    // port par dΘfaut
  2070. #endif
  2071.       if (a) {
  2072.         char BIGSTK iadr2[HTS_URLMAXSIZE*2];
  2073.         int i=-1;
  2074.         iadr2[0]='\0';
  2075.         sscanf(a+1,"%d",&i);
  2076.         if (i!=-1) {
  2077.           port=(unsigned short int) i;
  2078.         }
  2079.         
  2080.         // adresse vΘritable (sans :xx)
  2081.         strncatbuff(iadr2,iadr,(int) (a - iadr));
  2082.  
  2083.         // adresse sans le :xx
  2084.         hp = hts_gethostbyname(iadr2, &fullhostent_buffer);
  2085.         
  2086.       } else {
  2087.  
  2088.         // adresse normale (port par dΘfaut par la suite)
  2089.         hp = hts_gethostbyname(iadr, &fullhostent_buffer);
  2090.         
  2091.       }
  2092.       
  2093.     } else    // port dΘfini
  2094.       hp = hts_gethostbyname(iadr, &fullhostent_buffer);
  2095.  
  2096.     
  2097.     // Conversion iadr -> adresse
  2098.     // structure recevant le nom de l'h⌠te, etc
  2099.     //struct     hostent     *hp;
  2100.     if (hp == NULL) {
  2101. #if DEBUG
  2102.       printf("erreur gethostbyname\n");
  2103. #endif
  2104.       if (retour)
  2105.       if (retour->msg)
  2106. #ifdef _WIN32
  2107.         sprintf(retour->msg,"Unable to get server's address: %s", strerror(WSAGetLastError()));
  2108. #else
  2109.         sprintf(retour->msg,"Unable to get server's address: %s", strerror(errno));
  2110. #endif
  2111.       return INVALID_SOCKET;
  2112.     }  
  2113.     // copie adresse
  2114.     SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  2115.     // make a copy for external clients
  2116.     retour->address_size = sizeof(retour->address);
  2117.     SOCaddr_copyaddr(retour->address, retour->address_size, hp->h_addr_list[0], hp->h_length);
  2118.     // memcpy(&SOCaddr_sinaddr(server), hp->h_addr_list[0], hp->h_length);
  2119.      
  2120.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  2121. #if HDEBUG
  2122.     printf("socket\n");
  2123. #endif
  2124. #if HTS_WIDE_DEBUG    
  2125.     DEBUG_W("socket\n");
  2126. #endif
  2127.     soc=socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  2128.     if (retour != NULL) {
  2129.       retour->debugid = HTS_STAT.stat_sockid++;
  2130.     }
  2131. #if HTS_WIDE_DEBUG    
  2132.     DEBUG_W("socket()=%d\n" _ (int) soc);
  2133. #endif
  2134.     if (soc==INVALID_SOCKET) {
  2135.       if (retour)
  2136.       if (retour->msg)
  2137. #ifdef _WIN32
  2138.         sprintf(retour->msg,"Unable to create a socket: %s", strerror(WSAGetLastError()));
  2139. #else
  2140.         sprintf(retour->msg,"Unable to create a socket: %s", strerror(errno));
  2141. #endif
  2142.       return INVALID_SOCKET;                        // erreur crΘation socket impossible
  2143.     }
  2144.  
  2145.     // bind this address
  2146.     if (retour != NULL && retour->req.proxy.bindhost[0] != '\0') {
  2147.       t_fullhostent bind_buffer;
  2148.       hp = hts_gethostbyname(retour->req.proxy.bindhost, &bind_buffer);
  2149.       if (hp == NULL ||
  2150.         bind(soc, (struct sockaddr *)hp->h_addr_list[0], hp->h_length) != 0) {
  2151.         if (retour)
  2152.           if (retour->msg)
  2153. #ifdef _WIN32
  2154.             sprintf(retour->msg,"Unable to bind the specificied server address: %s", strerror(WSAGetLastError()));
  2155. #else
  2156.             sprintf(retour->msg,"Unable to bind the specificied server address: %s", strerror(errno));
  2157. #endif
  2158.           deletesoc(soc);
  2159.           return INVALID_SOCKET;
  2160.       }
  2161.     }
  2162.     
  2163.     // structure: connexion au domaine internet, port 80 (ou autre)
  2164.     SOCaddr_initport(server, port);
  2165. #if HDEBUG
  2166.     printf("==%d\n",soc);
  2167. #endif
  2168.  
  2169.     // connexion non bloquante?
  2170.     if (!waitconnect ) {
  2171.       unsigned long p=1;  // non bloquant
  2172. #if HTS_WIN
  2173.       ioctlsocket(soc,FIONBIO,&p);
  2174. #else
  2175.       ioctl(soc,FIONBIO,&p);
  2176. #endif
  2177.     }
  2178.     
  2179.     // Connexion au serveur lui mΩme
  2180. #if HDEBUG
  2181.     printf("connect\n");
  2182. #endif
  2183.     HTS_STAT.last_connect = mtime_local();
  2184.     
  2185. #if HTS_WIDE_DEBUG
  2186.     DEBUG_W("connect\n");
  2187. #endif
  2188. #if HTS_WIN
  2189.     if (connect(soc, (const struct sockaddr FAR *)&server, server_size) != 0) {
  2190. #else
  2191.       if (connect(soc, (struct sockaddr *)&server, server_size) == -1) {
  2192. #endif
  2193.  
  2194.         // bloquant
  2195.         if (waitconnect) {
  2196. #if HDEBUG
  2197.           printf("unable to connect!\n");
  2198. #endif
  2199.           if (retour)
  2200.           if (retour->msg)
  2201. #ifdef _WIN32
  2202.             sprintf(retour->msg,"Unable to connect to the server: %s", strerror(WSAGetLastError()));
  2203. #else
  2204.             sprintf(retour->msg,"Unable to connect to the server: %s", strerror(errno));
  2205. #endif
  2206.           /* Close the socket and notify the error!!! */
  2207.           deletesoc(soc);
  2208.           return INVALID_SOCKET;
  2209.         }
  2210.       }
  2211. #if HTS_WIDE_DEBUG    
  2212.       DEBUG_W("connect done\n");
  2213. #endif
  2214.       
  2215. #if HDEBUG
  2216.       printf("connexion Θtablie\n");
  2217. #endif
  2218.     
  2219.     // A partir de maintenant, on peut envoyer et recevoir des donnΘes
  2220.     // via le flot identifiΘ par soc (socket): write(soc,adr,taille) et 
  2221.     // read(soc,adr,taille)
  2222.  
  2223.   } else {    // on doit ouvrir un fichier local!
  2224.     // il sera gΘrΘ de la mΩme maniΦre qu'une socket (c'est idem!)
  2225.  
  2226.     soc=LOCAL_SOCKET_ID;    // pseudo-socket locale..
  2227.     // soc sera remplacΘ lors d'un http_fopen() par un handle vΘritable!
  2228.  
  2229.   }   // teste fichier local ou http
  2230.   
  2231.   return soc;
  2232. }
  2233.  
  2234.  
  2235.  
  2236. // couper http://www.truc.fr/pub/index.html -> www.truc.fr /pub/index.html
  2237. // retour=-1 si erreur.
  2238. // si file://... alors adresse=file:// (et coupe le ?query dans ce cas)
  2239. int ident_url_absolute(char* url,char* adr,char* fil) {
  2240.   int pos=0;
  2241.   int scheme=0;
  2242.  
  2243.   // effacer adr et fil
  2244.   adr[0]=fil[0]='\0';
  2245.   
  2246. #if HDEBUG
  2247.   printf("protocol: %s\n",url);
  2248. #endif
  2249.  
  2250.   // Scheme?
  2251.   {
  2252.     char* a=url;
  2253.     while (isalpha((unsigned char)*a))
  2254.       a++;
  2255.     if (*a == ':')
  2256.       scheme=1;
  2257.   }
  2258.  
  2259.   // 1. optional scheme ":"
  2260.   if ((pos=strfield(url,"file:"))) {    // fichier local!! (pour les tests)
  2261.     //!!p+=3;
  2262.     strcpybuff(adr,"file://");
  2263.   } else if ((pos=strfield(url,"http:"))) {    // HTTP
  2264.     //!!p+=3;
  2265.   } else if ((pos=strfield(url,"ftp:"))) {    // FTP
  2266.     strcpybuff(adr,"ftp://");    // FTP!!
  2267.     //!!p+=3;
  2268. #if HTS_USEOPENSSL
  2269.   } else if (SSL_is_available && (pos=strfield(url,"https:"))) {    // HTTPS
  2270.     strcpybuff(adr,"https://");
  2271. #endif
  2272. #if HTS_USEMMS
  2273.   } else if ((pos = strfield(url,"mms:"))) {    // mms
  2274.     strcpybuff(adr,"mms://");
  2275. #endif
  2276.   } else if (scheme) {
  2277.     return -1;    // erreur non reconnu
  2278.   } else
  2279.     pos=0;
  2280.  
  2281.   // 2. optional "//" authority
  2282.   if (strncmp(url+pos,"//",2)==0)
  2283.     pos+=2;
  2284.  
  2285.   // (url+pos) now points to the path (not net path)
  2286.  
  2287.   //## if (adr[0]!=lOCAL_CHAR) {    // adresse normale http
  2288.   if (!strfield(adr,"file:")) {      // PAS file://
  2289.     char *p,*q;
  2290.     p=url+pos;
  2291.  
  2292.     // p pointe sur le dΘbut de l'adresse, ex: www.truc.fr/sommaire/index.html
  2293.     q=strchr(jump_identification(p),'/');
  2294.     if (q==0) q=strchr(jump_identification(p),'?');     // http://www.foo.com?bar=1
  2295.     if (q==0) q=p+strlen(p);  // pointe sur \0
  2296.     // q pointe sur le chemin, ex: index.html?query=recherche
  2297.     
  2298.     // chemin www... trop long!!
  2299.     if ( ( ((int) (q - p)) )  > HTS_URLMAXSIZE) {
  2300.       //strcpybuff(retour.msg,"Path too long");
  2301.       return -1;    // erreur
  2302.     }
  2303.     
  2304.     // recopier adresse www..
  2305.     strncatbuff(adr,p, ((int) (q - p)) );
  2306.     // *( adr+( ((int) q) - ((int) p) ) )=0;  // faut arrΩter la fumette!
  2307.     // recopier chemin /pub/..
  2308.     if (q[0] != '/')    // page par dΘfaut (/)
  2309.       strcatbuff(fil,"/");
  2310.     strcatbuff(fil,q);
  2311.     // SECURITE:
  2312.     // simplifier url pour les ../
  2313.     fil_simplifie(fil);
  2314.   } else {    // localhost file://
  2315.     char *p;
  2316.     int i;
  2317.     char* a;
  2318.     
  2319.     p=url+pos;
  2320.     if (*p == '/' || *p == '\\') {  /* file:///.. */
  2321.       strcatbuff(fil,p);    // fichier local ; adr="#"
  2322.     } else {
  2323.       if (p[1] != ':') {
  2324.         strcatbuff(fil,"//");   /* file://server/foo */
  2325.         strcatbuff(fil,p);
  2326.       } else {
  2327.         strcatbuff(fil,p);    // file://C:\..
  2328.       }
  2329.     }
  2330.     
  2331.     a=strchr(fil,'?');
  2332.     if (a) 
  2333.       *a='\0';      /* couper query (inutile pour file:// lors de la requΩte) */
  2334.     // filtrer les \\ -> / pour les fichiers DOS
  2335.     for(i=0;i<(int) strlen(fil);i++)
  2336.       if (fil[i]=='\\')
  2337.         fil[i]='/';
  2338.   }
  2339.  
  2340.   // no hostname
  2341.   if (!strnotempty(adr))
  2342.     return -1;    // erreur non reconnu
  2343.  
  2344.   // nommer au besoin.. (non utilisΘ normalement)
  2345.   if (!strnotempty(fil))
  2346.     strcpybuff(fil,"default-index.html");
  2347.  
  2348.   // case insensitive pour adresse
  2349.   {
  2350.     char *a=jump_identification(adr);
  2351.     while(*a) {
  2352.       if ((*a>='A') && (*a<='Z'))
  2353.         *a+='a'-'A';       
  2354.       a++;
  2355.     }
  2356.   }
  2357.   
  2358.   return 0;
  2359. }
  2360.  
  2361. /* simplify ../ and ./ */
  2362. void fil_simplifie(char* f) {
  2363.   char *a, *b;
  2364.   char *rollback[128];
  2365.   int rollid = 0;
  2366.   char lc = '/';
  2367.   int query = 0;
  2368.   int wasAbsolute = (*f == '/');
  2369.   for(a = b = f ; *a != '\0' ; ) {
  2370.     if (*a == '?')
  2371.       query = 1;
  2372.     if (query == 0 && lc == '/' && a[0] == '.' && a[1] == '/') {    /* foo/./bar or ./foo  */
  2373.       a += 2;
  2374.     }
  2375.     else if (query == 0 && lc == '/' && a[0] == '.' && a[1] == '.' && ( a[2] == '/' || a[2] == '\0' ) ) {    /* foo/../bar or ../foo or .. */
  2376.       if (a[2] == '\0')
  2377.         a += 2;
  2378.       else
  2379.         a += 3;
  2380.       if (rollid > 1) {
  2381.         rollid--;
  2382.         b = rollback[rollid - 1];
  2383.       } else {   /* too many ../ */
  2384.         rollid = 0;
  2385.         b = f;
  2386.         if (wasAbsolute)
  2387.           b++;   /* after the / */
  2388.       }
  2389.     }
  2390.     else {
  2391.       *b++ = lc = *a;
  2392.       if (*a == '/') {
  2393.         rollback[rollid++] = b;
  2394.         if (rollid >= 127) {
  2395.           *f = '\0';      /* ERROR */
  2396.           break;
  2397.         }
  2398.       }
  2399.       a++;
  2400.     }
  2401.   }
  2402.   *b = '\0';
  2403.   if (*f == '\0') {
  2404.     if (wasAbsolute) {
  2405.       f[0] = '/';
  2406.       f[1] = '\0';
  2407.     } else {
  2408.       f[0] = '.';
  2409.       f[1] = '/';
  2410.       f[2] = '\0';
  2411.     }
  2412.   }
  2413. }
  2414.  
  2415. // fermer liaison fichier ou socket
  2416. HTS_INLINE void deletehttp(htsblk* r) {
  2417. #if HTS_DEBUG_CLOSESOCK
  2418.     DEBUG_W("deletehttp: (htsblk*) 0x%p\n" _ (void*) r);
  2419. #endif
  2420. #if HTS_USEOPENSSL
  2421.     /* Free OpenSSL structures */
  2422.     if (SSL_is_available && r->ssl_con) {
  2423.       SSL_shutdown(r->ssl_con);
  2424.       SSL_free(r->ssl_con);
  2425.       r->ssl_con=NULL;
  2426.     }
  2427. #endif  
  2428.   if (r->soc!=INVALID_SOCKET) {
  2429.     if (r->is_file) {
  2430.       if (r->fp)
  2431.         fclose(r->fp);
  2432.       r->fp=NULL;
  2433.     } else {
  2434.       if (r->soc!=LOCAL_SOCKET_ID)
  2435.         deletesoc_r(r);
  2436.     }
  2437.     r->soc=INVALID_SOCKET;
  2438.   }
  2439. }
  2440.  
  2441. // free the addr buffer
  2442. // always returns 1
  2443. HTS_INLINE int deleteaddr(htsblk* r) {
  2444.   if (r->adr != NULL) {
  2445.     freet(r->adr);
  2446.     r->adr = NULL;
  2447.   }
  2448.   if (r->headers != NULL) {
  2449.     freet(r->headers);
  2450.     r->headers = NULL;
  2451.   }
  2452.   return 1;
  2453. }
  2454.  
  2455. // fermer une socket
  2456. HTS_INLINE void deletesoc(T_SOC soc) {
  2457.   if (soc!=INVALID_SOCKET && soc!=LOCAL_SOCKET_ID) {
  2458. #if HTS_WIDE_DEBUG    
  2459.     DEBUG_W("close %d\n" _ (int) soc);
  2460. #endif
  2461. #if HTS_WIN
  2462.     closesocket(soc);
  2463. #else
  2464.     close(soc);
  2465. #endif
  2466. #if HTS_WIDE_DEBUG    
  2467.     DEBUG_W(".. done\n");
  2468. #endif
  2469.   }
  2470. }
  2471.  
  2472. /* Will also clean other things */
  2473. HTS_INLINE void deletesoc_r(htsblk* r) {
  2474. #if HTS_USEOPENSSL
  2475.   if (SSL_is_available && r->ssl_con) {
  2476.     SSL_shutdown(r->ssl_con);
  2477.     // SSL_CTX_set_quiet_shutdown(r->ssl_con->ctx, 1);
  2478.     SSL_free(r->ssl_con);
  2479.     r->ssl_con=NULL;
  2480.   }
  2481. #endif
  2482.   if (r->soc!=INVALID_SOCKET) {
  2483.     deletesoc(r->soc);
  2484.     r->soc=INVALID_SOCKET;
  2485.   }
  2486. }
  2487.  
  2488. // renvoi le nombre de secondes depuis 1970
  2489. HTS_INLINE TStamp time_local(void) {
  2490.   return ((TStamp) time(NULL));
  2491. }
  2492.  
  2493. // number of millisec since 1970
  2494. HTSEXT_API HTS_INLINE TStamp mtime_local(void) {
  2495. #ifndef HTS_DO_NOT_USE_FTIME
  2496.   struct timeb B;
  2497.   ftime( &B );
  2498.   return (TStamp) ( ((TStamp) B.time * (TStamp) 1000)
  2499.         + ((TStamp) B.millitm) );
  2500. #else
  2501.   // not precise..
  2502.   return (TStamp) ( ((TStamp) time_local() * (TStamp) 1000)
  2503.         + ((TStamp) 0) );
  2504. #endif
  2505. }
  2506.  
  2507. // convertit un nombre de secondes en temps (chaine)
  2508. void sec2str(char *st,TStamp t) {
  2509.   int j,h,m,s;
  2510.   
  2511.   j=(int) (t/(3600*24));
  2512.   t-=((TStamp) j)*(3600*24);
  2513.   h=(int) (t/(3600));
  2514.   t-=((TStamp) h)*3600;
  2515.   m=(int) (t/60);
  2516.   t-=((TStamp) m)*60;
  2517.   s=(int) t;
  2518.   
  2519.   if (j>0)
  2520.     sprintf(st,"%d days, %d hours %d minutes %d seconds",j,h,m,s);
  2521.   else if (h>0)
  2522.     sprintf(st,"%d hours %d minutes %d seconds",h,m,s);
  2523.   else if (m>0)
  2524.     sprintf(st,"%d minutes %d seconds",m,s);
  2525.   else
  2526.     sprintf(st,"%d seconds",s);
  2527. }
  2528.  
  2529. // idem, plus court (chaine)
  2530. HTSEXT_API void qsec2str(char *st,TStamp t) {
  2531.   int j,h,m,s;
  2532.   
  2533.   j=(int) (t/(3600*24));
  2534.   t-=((TStamp) j)*(3600*24);
  2535.   h=(int) (t/(3600));
  2536.   t-=((TStamp) h)*3600;
  2537.   m=(int) (t/60);
  2538.   t-=((TStamp) m)*60;
  2539.   s=(int) t;
  2540.   
  2541.   if (j>0)
  2542.     sprintf(st,"%dd,%02dh,%02dmin%02ds",j,h,m,s);
  2543.   else if (h>0)
  2544.     sprintf(st,"%dh,%02dmin%02ds",h,m,s);
  2545.   else if (m>0)
  2546.     sprintf(st,"%dmin%02ds",m,s);
  2547.   else
  2548.     sprintf(st,"%ds",s);
  2549. }
  2550.  
  2551.  
  2552. // heure actuelle, GMT, format rfc (taille buffer 256o)
  2553. void time_gmt_rfc822(char* s) {
  2554.   time_t tt;
  2555.   struct tm* A;
  2556.   tt=time(NULL);
  2557.   A=gmtime(&tt);
  2558.   if (A==NULL)
  2559.     A=localtime(&tt);
  2560.   time_rfc822(s,A);
  2561. }
  2562.  
  2563. // heure actuelle, format rfc (taille buffer 256o)
  2564. void time_local_rfc822(char* s) {
  2565.   time_t tt;
  2566.   struct tm* A;
  2567.   tt=time(NULL);
  2568.   A=localtime(&tt);
  2569.   time_rfc822_local(s,A);
  2570. }
  2571.  
  2572. /* convertir une chaine en temps */
  2573. struct tm* convert_time_rfc822(char* s) {
  2574.   struct tm* result;
  2575.   /* */
  2576.   char months[]="jan feb mar apr may jun jul aug sep oct nov dec";
  2577.   char str[256];
  2578.   char* a;
  2579.   /* */
  2580.   int result_mm=-1;
  2581.   int result_dd=-1;
  2582.   int result_n1=-1;
  2583.   int result_n2=-1;
  2584.   int result_n3=-1;
  2585.   int result_n4=-1;
  2586.   /* */
  2587.   NOSTATIC_RESERVE(result, struct tm, 1);
  2588.  
  2589.   if ((int) strlen(s) > 200)
  2590.     return NULL;
  2591.   strcpybuff(str,s);
  2592.   hts_lowcase(str);
  2593.   /* Θliminer :,- */
  2594.   while( (a=strchr(str,'-')) ) *a=' ';
  2595.   while( (a=strchr(str,':')) ) *a=' ';
  2596.   while( (a=strchr(str,',')) ) *a=' ';
  2597.   /* tokeniser */
  2598.   a=str;
  2599.   while(*a) {
  2600.     char *first,*last;
  2601.     char tok[256];
  2602.     /* dΘcouper mot */
  2603.     while(*a==' ') a++;   /* sauter espaces */
  2604.     first=a;
  2605.     while((*a) && (*a!=' ')) a++;
  2606.     last=a;
  2607.     tok[0]='\0';
  2608.     if (first!=last) {
  2609.       char* pos;
  2610.       strncatbuff(tok,first,(int) (last - first));
  2611.       /* analyser */
  2612.       if ( (pos=strstr(months,tok)) ) {               /* month always in letters */
  2613.         result_mm=((int) (pos - months))/4;
  2614.       } else {
  2615.         int number;
  2616.         if (sscanf(tok,"%d",&number) == 1) {      /* number token */
  2617.           if (result_dd<0)                        /* day always first number */
  2618.             result_dd=number;
  2619.           else if (result_n1<0)
  2620.             result_n1=number;
  2621.           else if (result_n2<0)
  2622.             result_n2=number;
  2623.           else if (result_n3<0)
  2624.             result_n3=number;
  2625.           else if (result_n4<0)
  2626.             result_n4=number;
  2627.         }   /* sinon, bruit de fond(+1GMT for exampel) */
  2628.       }
  2629.     }
  2630.   }
  2631.   if ((result_n1>=0) && (result_mm>=0) && (result_dd>=0) && (result_n2>=0) && (result_n3>=0) && (result_n4>=0)) {
  2632.     if (result_n4>=1000) {               /* Sun Nov  6 08:49:37 1994 */
  2633.       result->tm_year=result_n4-1900;
  2634.       result->tm_hour=result_n1;
  2635.       result->tm_min=result_n2;
  2636.       result->tm_sec=max(result_n3,0);
  2637.     } else {                            /* Sun, 06 Nov 1994 08:49:37 GMT or Sunday, 06-Nov-94 08:49:37 GMT */
  2638.       result->tm_hour=result_n2;
  2639.       result->tm_min=result_n3;
  2640.       result->tm_sec=max(result_n4,0);
  2641.       if (result_n1<=50)                /* 00 means 2000 */
  2642.         result->tm_year=result_n1+100;
  2643.       else if (result_n1<1000)          /* 99 means 1999 */
  2644.         result->tm_year=result_n1;
  2645.       else                              /* 2000 */
  2646.         result->tm_year=result_n1-1900;
  2647.     }
  2648.     result->tm_isdst=0;        /* assume GMT */
  2649.     result->tm_yday=-1;        /* don't know */
  2650.     result->tm_wday=-1;        /* don't know */
  2651.     result->tm_mon=result_mm;
  2652.     result->tm_mday=result_dd;
  2653.     return result;
  2654.   }
  2655.   return NULL;
  2656. }
  2657.  
  2658. /* sets file time. -1 if error */
  2659. int set_filetime(char* file,struct tm* tm_time) {
  2660.   struct utimbuf tim;
  2661. #ifndef HTS_DO_NOT_USE_FTIME
  2662.   struct timeb B;
  2663.   B.timezone=0;
  2664.   ftime( &B );
  2665.   tim.actime=tim.modtime=mktime(tm_time) - B.timezone*60; 
  2666. #else
  2667.   // bogus time (GMT/local)..
  2668.   tim.actime=tim.modtime=mktime(tm_time); 
  2669. #endif
  2670.   return utime(file,&tim);
  2671. }
  2672.  
  2673. /* sets file time from RFC822 date+time, -1 if error*/
  2674. int set_filetime_rfc822(char* file,char* date) {
  2675.   struct tm* tm_s=convert_time_rfc822(date);
  2676.   if (tm_s) {
  2677.     return set_filetime(file,tm_s);
  2678.   } else return -1;
  2679. }
  2680.  
  2681. int get_filetime_rfc822(char* file,char* date) {
  2682.   struct stat buf;
  2683.   date[0] = '\0';
  2684.   if (stat(file, &buf) == 0) {
  2685.     struct tm* A;
  2686.     time_t tt = buf.st_mtime;
  2687.     A=gmtime(&tt);
  2688.     if (A==NULL)
  2689.       A=localtime(&tt);
  2690.     if (A != NULL) {
  2691.       time_rfc822(date, A);
  2692.       return 1;
  2693.     }
  2694.   }
  2695.   return 0;
  2696. }
  2697.  
  2698. // heure au format rfc (taille buffer 256o)
  2699. HTS_INLINE void time_rfc822(char* s,struct tm * A) {
  2700.   if (A == NULL) {
  2701.     int localtime_returned_null=0;
  2702.     assert(localtime_returned_null);
  2703.   }
  2704.   strftime(s,256,"%a, %d %b %Y %H:%M:%S GMT",A);
  2705. }
  2706.  
  2707. // heure locale au format rfc (taille buffer 256o)
  2708. HTS_INLINE void time_rfc822_local(char* s,struct tm * A) {
  2709.   if (A == NULL) {
  2710.     int localtime_returned_null=0;
  2711.     assert(localtime_returned_null);
  2712.   }
  2713.   strftime(s,256,"%a, %d %b %Y %H:%M:%S",A);
  2714. }
  2715.  
  2716. // conversion en b,Kb,Mb
  2717. HTSEXT_API char* int2bytes(LLint n) {
  2718.   char** a=int2bytes2(n);
  2719.   char* buff;
  2720.   NOSTATIC_RESERVE(buff, char, 256);
  2721.  
  2722.   strcpybuff(buff,a[0]);
  2723.   strcatbuff(buff,a[1]);
  2724.   return concat(buff,"");
  2725. }
  2726.  
  2727. // conversion en b/s,Kb/s,Mb/s
  2728. HTSEXT_API char* int2bytessec(long int n) {
  2729.   char* buff;
  2730.   char** a=int2bytes2(n);
  2731.   NOSTATIC_RESERVE(buff, char, 256);
  2732.  
  2733.   strcpybuff(buff,a[0]);
  2734.   strcatbuff(buff,a[1]);
  2735.   return concat(buff,"/s");
  2736. }
  2737. HTSEXT_API char* int2char(int n) {
  2738.   char* buffer;
  2739.   NOSTATIC_RESERVE(buffer, char, 32);
  2740.   sprintf(buffer,"%d",n);
  2741.   return concat(buffer,"");
  2742. }
  2743.  
  2744. // conversion en b,Kb,Mb, nombre et type sΘparΘs
  2745. // limite: 2.10^9.10^6B
  2746.  
  2747. /* See http://physics.nist.gov/cuu/Units/binary.html */
  2748. #define ToLLint(a) ((LLint)(a))
  2749. #define ToLLintKiB (ToLLint(1024))
  2750. #define ToLLintMiB (ToLLintKiB*ToLLintKiB)
  2751. #ifdef HTS_LONGLONG
  2752. #define ToLLintGiB (ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2753. #define ToLLintTiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2754. #define ToLLintPiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2755. #endif
  2756. typedef struct {
  2757.   char buff1[256];
  2758.   char buff2[32];
  2759.   char* buffadr[2];
  2760. } strc_int2bytes2;
  2761. HTSEXT_API char** int2bytes2(LLint n) {
  2762.   strc_int2bytes2* strc;
  2763.   NOSTATIC_RESERVE(strc, strc_int2bytes2, 1);
  2764.  
  2765.   if (n < ToLLintKiB) {
  2766.     sprintf(strc->buff1,"%d",(int)(LLint)n);
  2767.     strcpybuff(strc->buff2,"B");
  2768.   } else if (n < ToLLintMiB) {
  2769.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/ToLLintKiB)),(int)((LLint)((n%ToLLintKiB)*100)/ToLLintKiB));
  2770.     strcpybuff(strc->buff2,"KiB");
  2771.   }
  2772. #ifdef HTS_LONGLONG
  2773.   else if (n < ToLLintGiB) {
  2774.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB))));
  2775.     strcpybuff(strc->buff2,"MiB");
  2776.   } else if (n < ToLLintTiB) {
  2777.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintGiB))),(int)((LLint)(((n%(ToLLintGiB))*100)/(ToLLintGiB))));
  2778.     strcpybuff(strc->buff2,"GiB");
  2779.   } else if (n < ToLLintPiB) {
  2780.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintTiB))),(int)((LLint)(((n%(ToLLintTiB))*100)/(ToLLintTiB))));
  2781.     strcpybuff(strc->buff2,"TiB");
  2782.   } else {
  2783.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintPiB))),(int)((LLint)(((n%(ToLLintPiB))*100)/(ToLLintPiB))));
  2784.     strcpybuff(strc->buff2,"PiB");
  2785.   }
  2786. #else
  2787.   else {
  2788.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB))));
  2789.     strcpybuff(strc->buff2,"MiB");
  2790.   }
  2791. #endif
  2792.   strc->buffadr[0]=strc->buff1;
  2793.   strc->buffadr[1]=strc->buff2;
  2794.   return strc->buffadr;
  2795. }
  2796.  
  2797. #if HTS_WIN
  2798. #else
  2799. // ignore sigpipe?
  2800. int sig_ignore_flag( int setflag ) {     // flag ignore
  2801.   static int flag=0;   /* YES, this one is true static */
  2802.   if (setflag>=0)
  2803.     flag=setflag;
  2804.   return flag;
  2805. }
  2806. #endif
  2807.  
  2808. // envoi de texte (en tΩtes gΘnΘralement) sur la socket soc
  2809. HTS_INLINE int sendc(htsblk* r, char* s) {
  2810.   int n, ssz = (int)strlen(s);
  2811.  
  2812. #if HTS_WIN
  2813. #else
  2814.   sig_ignore_flag(1);
  2815. #endif
  2816. #if HDEBUG
  2817.   write(0,s,ssz);
  2818. #endif
  2819.  
  2820. #if HTS_USEOPENSSL
  2821.   if (SSL_is_available && r->ssl) {
  2822.     n = SSL_write(r->ssl_con, s, ssz);
  2823.   } else
  2824. #endif
  2825.     n = send(r->soc,s,ssz,0);
  2826.  
  2827. #if HTS_WIN
  2828. #else
  2829.   sig_ignore_flag(0);
  2830. #endif
  2831.  
  2832.   return ( n == ssz ) ? n : -1;
  2833. }
  2834.  
  2835.  
  2836. // Remplace read
  2837. int finput(int fd,char* s,int max) {
  2838.   char c;
  2839.   int j=0;
  2840.   do {
  2841.     //c=fgetc(fp);
  2842.     if (read(fd,&c,1)<=0) {
  2843.       c=0;
  2844.     }
  2845.     if (c!=0) {
  2846.       switch(c) {
  2847.       case 10: c=0; break;
  2848.       case 13: break;  // sauter ces caractΦres
  2849.       default: s[j++]=c; break;
  2850.       }
  2851.     }
  2852.   }  while((c!=0) && (j<max-1));
  2853.   s[j]='\0';
  2854.   return j;
  2855.  
  2856. // Like linput, but in memory (optimized)
  2857. int binput(char* buff, char* s, int max) {
  2858.   int count = 0;
  2859.   int destCount = 0;
  2860.  
  2861.   // Note: \0 will return 1
  2862.   while(destCount < max && buff != NULL && buff[count] != '\0' && buff[count] != '\n') {
  2863.     if (buff[count] != '\r') {
  2864.       s[destCount++] = buff[count];
  2865.     }
  2866.     count++;
  2867.   }
  2868.   s[destCount] = '\0';
  2869.  
  2870.   // then return the supplemental jump offset
  2871.   return count + 1;
  2872.  
  2873. // Lecture d'une ligne (peut Ωtre unicode α priori)
  2874. int linput(FILE* fp,char* s,int max) {
  2875.   int c;
  2876.   int j=0;
  2877.   do {
  2878.     c=fgetc(fp);
  2879.     if (c!=EOF) {
  2880.       switch(c) {
  2881.         case 13: break;  // sauter CR
  2882.         case 10: c=-1; break;
  2883.         case 9: case 12: break;  // sauter ces caractΦres
  2884.         default: s[j++]=(char) c; break;
  2885.       }
  2886.     }
  2887.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2888.   s[j]='\0';
  2889.   return j;
  2890. }
  2891. int linputsoc(T_SOC soc, char* s, int max) {
  2892.   int c;
  2893.   int j=0;
  2894.   do {
  2895.     unsigned char ch;
  2896.     if (recv(soc, &ch, 1, 0) == 1) {
  2897.       c = ch;
  2898.     } else {
  2899.       c = EOF;
  2900.     }
  2901.     if (c!=EOF) {
  2902.       switch(c) {
  2903.         case 13: break;  // sauter CR
  2904.         case 10: c=-1; break;
  2905.         case 9: case 12: break;  // sauter ces caractΦres
  2906.         default: s[j++]=(char) c; break;
  2907.       }
  2908.     }
  2909.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2910.   s[j]='\0';
  2911.   return j;
  2912. }
  2913. int linputsoc_t(T_SOC soc, char* s, int max, int timeout) {
  2914.   if (check_readinput_t(soc, timeout)) {
  2915.     return linputsoc(soc, s, max);
  2916.   }
  2917.   return -1;
  2918. }
  2919. int linput_trim(FILE* fp,char* s,int max) {
  2920.   int rlen=0;
  2921.   char* ls=(char*) malloct(max+2);
  2922.   s[0]='\0';
  2923.   if (ls) {
  2924.     char* a;
  2925.     // lire ligne
  2926.     rlen=linput(fp,ls,max);
  2927.     if (rlen) {
  2928.       // sauter espaces et tabs en fin
  2929.       while( (rlen>0) && ((ls[max(rlen-1,0)]==' ') || (ls[max(rlen-1,0)]=='\t')) )
  2930.         ls[--rlen]='\0';
  2931.       // sauter espaces en dΘbut
  2932.       a=ls;
  2933.       while((rlen>0) && ((*a==' ') || (*a=='\t'))) {
  2934.         a++;
  2935.         rlen--;
  2936.       }
  2937.       if (rlen>0) {
  2938.         memcpy(s,a,rlen);      // can copy \0 chars
  2939.         s[rlen]='\0';
  2940.       }
  2941.     }
  2942.     //
  2943.     freet(ls);
  2944.   }
  2945.   return rlen;
  2946. }
  2947. int linput_cpp(FILE* fp,char* s,int max) {
  2948.   int rlen=0;
  2949.   s[0]='\0';
  2950.   do {
  2951.     int ret;
  2952.     if (rlen>0)
  2953.     if (s[rlen-1]=='\\')
  2954.       s[--rlen]='\0';      // couper \ final
  2955.     // lire ligne
  2956.     ret=linput_trim(fp,s+rlen,max-rlen);
  2957.     if (ret>0)
  2958.       rlen+=ret;
  2959.   } while((s[max(rlen-1,0)]=='\\') && (rlen<max));
  2960.   return rlen;
  2961. }
  2962.  
  2963. // idem avec les car spΘciaux
  2964. void rawlinput(FILE* fp,char* s,int max) {
  2965.   int c;
  2966.   int j=0;
  2967.   do {
  2968.     c=fgetc(fp);
  2969.     if (c!=EOF) {
  2970.       switch(c) {
  2971.         case 13: break;  // sauter CR
  2972.         case 10: c=-1; break;
  2973.         default: s[j++]=(char) c; break;
  2974.       }
  2975.     }
  2976.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2977.   s[j++]='\0';
  2978. }
  2979.  
  2980. //cherche chaine, case insensitive
  2981. char* strstrcase(char *s,char *o) {
  2982.   while((*s) && (strfield(s,o)==0)) s++;
  2983.   if (*s=='\0') return NULL;
  2984.   return s;  
  2985. }
  2986.  
  2987.  
  2988. // Unicode detector
  2989. // See http://www.unicode.org/unicode/reports/tr28/
  2990. // (sect Table 3.1B. Legal UTF-8 Byte Sequences)
  2991. typedef struct {
  2992.   unsigned int pos;
  2993.   unsigned char data[4];
  2994. } t_auto_seq;
  2995.  
  2996. // char between a and b
  2997. #define CHAR_BETWEEN(c, a, b)       ( (c) >= 0x##a ) && ( (c) <= 0x##b )
  2998. // sequence start
  2999. #define SEQBEG                      ( inseq == 0 )
  3000. // in this block
  3001. #define BLK(n,a, b)                 ( (seq.pos >= n) && ((err = CHAR_BETWEEN(seq.data[n], a, b))) )
  3002. #define ELT(n,a)                    BLK(n,a,a)
  3003. // end
  3004. #define SEQEND                      ((ok = 1))
  3005. // sequence started, character will fail if error
  3006. #define IN_SEQ                      ( (inseq = 1) )
  3007. // decoding error
  3008. #define BAD_SEQ                     ( (ok == 0) && (inseq != 0) && (!err) )
  3009. // no sequence started
  3010. #define NO_SEQ                      ( inseq == 0 )
  3011.  
  3012. // is this block an UTF unicode textfile?
  3013. // 0 : no
  3014. // 1 : yes
  3015. // -1: don't know
  3016. int is_unicode_utf8(unsigned char* buffer, unsigned int size) {
  3017.   t_auto_seq seq;
  3018.   unsigned int i;
  3019.   int is_utf=-1;
  3020.  
  3021.   seq.pos=0;
  3022.   for(i=0 ; i < size ; i++) {
  3023.     unsigned int ok=0;
  3024.     unsigned int inseq=0;
  3025.     unsigned int err=0;
  3026.  
  3027.     seq.data[seq.pos]=buffer[i];
  3028.     /**/ if ( SEQBEG && BLK(0,00,7F) && IN_SEQ && SEQEND                                                 ) { }
  3029.     else if ( SEQBEG && BLK(0,C2,DF) && IN_SEQ && BLK(1,80,BF) && SEQEND                                 ) { }
  3030.     else if ( SEQBEG && ELT(0,E0   ) && IN_SEQ && BLK(1,A0,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  3031.     else if ( SEQBEG && BLK(0,E1,EC) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  3032.     else if ( SEQBEG && ELT(0,ED   ) && IN_SEQ && BLK(1,80,9F) && BLK(2,80,BF) && SEQEND                 ) { }
  3033.     else if ( SEQBEG && BLK(0,EE,EF) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  3034.     else if ( SEQBEG && ELT(0,F0   ) && IN_SEQ && BLK(1,90,BF) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  3035.     else if ( SEQBEG && BLK(0,F1,F3) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  3036.     else if ( SEQBEG && ELT(0,F4   ) && IN_SEQ && BLK(1,80,8F) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  3037.     else if ( NO_SEQ ) {    // bad, unknown
  3038.       return 0;
  3039.     }
  3040.     /* */
  3041.     
  3042.     /* Error */
  3043.     if ( BAD_SEQ ) {
  3044.       return 0;
  3045.     }
  3046.  
  3047.     /* unicode character */
  3048.     if (seq.pos > 0)
  3049.       is_utf=1;
  3050.  
  3051.     /* Next */
  3052.     if (ok)
  3053.       seq.pos=0;
  3054.     else
  3055.       seq.pos++;
  3056.  
  3057.     /* Internal error */
  3058.     if (seq.pos >= 4)
  3059.       return 0;
  3060.  
  3061.   }
  3062.  
  3063.   return is_utf;
  3064. }
  3065.  
  3066. void map_characters(unsigned char* buffer, unsigned int size, unsigned int* map) {
  3067.   unsigned int i;
  3068.   memset(map, 0, sizeof(unsigned int) * 256);
  3069.   for(i = 0 ; i < size ; i++) {
  3070.     map[buffer[i]]++;
  3071.   }
  3072. }
  3073.  
  3074.  
  3075. // le fichier est-il un fichier html?
  3076. //  0 : non
  3077. //  1 : oui
  3078. // -1 : on sait pas
  3079. // -2 : on sait pas, pas d'extension
  3080. int ishtml(const char* fil) {
  3081.   /* User-defined MIME types (overrides ishtml()) */
  3082.   char BIGSTK fil_noquery[HTS_URLMAXSIZE*2];
  3083.   char mime[256];
  3084.   char* a;
  3085.   strcpybuff(fil_noquery, fil);
  3086.   if ((a = strchr(fil_noquery, '?')) != NULL) {
  3087.     *a = '\0';
  3088.   }
  3089.   if (get_userhttptype(0, mime, fil_noquery)) {
  3090.     if (strfield2(mime, "text/html")) {
  3091.       return 1;
  3092.     } else {
  3093.       return 0;
  3094.     }
  3095.   }
  3096.  
  3097.   /* Search for known ext */
  3098.   for (a = fil_noquery + strlen(fil_noquery) - 1 ; (*a!='.') && (*a!='/')  && ( a > fil_noquery ) ; a-- );
  3099.   if (*a == '.') {  // a une extension
  3100.     char BIGSTK fil_noquery[HTS_URLMAXSIZE*2];
  3101.     char* b;
  3102.     int ret;
  3103.     char* dotted = a;
  3104.     fil_noquery[0]='\0';
  3105.     a++;  // pointer sur extension
  3106.     strncatbuff(fil_noquery,a,HTS_URLMAXSIZE);
  3107.     b=strchr(fil_noquery,'?');
  3108.     if (b)
  3109.       *b='\0';
  3110.     ret = ishtml_ext(fil_noquery);     // retour
  3111.     if (ret == -1) {
  3112.       switch(is_knowntype(dotted)) {
  3113.       case 1:
  3114.         ret = 0;     // connu, non html
  3115.         break;
  3116.       case 2:
  3117.         ret = 1;     // connu, html
  3118.         break;
  3119.       default:
  3120.         ret = -1;    // inconnu..
  3121.         break;
  3122.       }
  3123.     }
  3124.     return ret;
  3125.   } else return -2;   // indΘterminΘ, par exemple /truc
  3126. }
  3127.  
  3128. // idem, mais pour uniquement l'extension
  3129. int ishtml_ext(const char* a) {
  3130.   int html=0;  
  3131.   //
  3132.   if (strfield2(a,"html"))       html = 1;
  3133.   else if (strfield2(a,"htm"))   html = 1;
  3134.   else if (strfield2(a,"shtml")) html = 1;
  3135.   else if (strfield2(a,"phtml")) html = 1;
  3136.   else if (strfield2(a,"htmlx")) html = 1;
  3137.   else if (strfield2(a,"shtm"))  html = 1;
  3138.   else if (strfield2(a,"phtm"))  html = 1;
  3139.   else if (strfield2(a,"htmx"))  html = 1;
  3140.   //
  3141.   // insuccΦs..
  3142.   else {
  3143. #if 1
  3144.     html = -1;    // inconnu..
  3145. #else
  3146.     // XXXXXX not suitable (ext)
  3147.     switch(is_knownext(a)) {
  3148.     case 1:
  3149.       html = 0;     // connu, non html
  3150.       break;
  3151.     case 2:
  3152.       html = 1;     // connu, html
  3153.       break;
  3154.     default:
  3155.       html = -1;    // inconnu..
  3156.       break;
  3157.     }
  3158. #endif
  3159.   }
  3160.   return html;  
  3161. }
  3162.  
  3163. // error (404,500..)
  3164. HTS_INLINE int ishttperror(int err) {
  3165.   switch (err/100) {
  3166.     case 4: case 5: return 1;
  3167.       break;
  3168.   }
  3169.   return 0;
  3170. }
  3171.  
  3172.  
  3173. // retourne le pointeur ou le pointeur + offset si il existe dans la chaine un @ signifiant 
  3174. // une identification
  3175. HTSEXT_API char* jump_identification(char* source) {
  3176.   char *a,*trytofind;
  3177.   if (strcmp(source, "file://") == 0)
  3178.       return source;
  3179.   // rechercher dernier @ (car parfois email transmise dans adresse!)
  3180.   // mais sauter ftp:// Θventuel
  3181.   a = jump_protocol(source);
  3182.   trytofind = strrchr_limit(a, '@', strchr(a,'/'));
  3183.   return (trytofind != NULL)?trytofind:a;
  3184. }
  3185.  
  3186. HTSEXT_API char* jump_normalized(char* source) {
  3187.   if (strcmp(source, "file://") == 0)
  3188.       return source;
  3189.   source = jump_identification(source); 
  3190.   if (strfield(source, "www") && source[3] != '\0') {
  3191.     if (source[3] == '.') {       // www.foo.com -> foo.com
  3192.       source += 4;  
  3193.     } else {                      // www-4.foo.com -> foo.com
  3194.       char* a = source + 3;
  3195.       while(*a && ( isdigit(*a) || *a == '-') ) a++;
  3196.       if (*a == '.') {
  3197.         source = a + 1;
  3198.       }
  3199.     }
  3200.   }
  3201.   return source;  
  3202. }
  3203.  
  3204. static int sortNormFnc(const void * a_, const void * b_) {
  3205.   char** a = (char**) a_;
  3206.   char** b = (char**) b_;
  3207.   return strcmp(*a+1, *b+1);
  3208. }
  3209.  
  3210.  
  3211. HTSEXT_API char* fil_normalized(char* source, char* dest) {
  3212.   char lastc = 0;
  3213.   int gotquery=0;
  3214.   int ampargs=0;
  3215.   int i,j;
  3216.   char* query=NULL;
  3217.   for(i=j=0 ; source[i] != '\0'; i++) {
  3218.     if (!gotquery && source[i] == '?')
  3219.       gotquery=ampargs=1;
  3220.     if ( 
  3221.       (!gotquery && lastc == '/' && source[i] == '/')  // foo//bar -> foo/bar
  3222.       ) {
  3223.     }
  3224.     else {
  3225.       if (gotquery && source[i] == '&') {
  3226.         ampargs++;
  3227.       }
  3228.       dest[j++] = source[i];
  3229.     }
  3230.     lastc = source[i];
  3231.   }
  3232.   dest[j++] = '\0';
  3233.  
  3234.   /* Sort arguments (&foo=1&bar=2 == &bar=2&foo=1) */
  3235.   if (ampargs > 1) {
  3236.     char** amps = malloct(ampargs * sizeof(char*));
  3237.     char* copyBuff = NULL;
  3238.     int qLen=0;
  3239.     assertf(amps != NULL);
  3240.     gotquery = 0;
  3241.     for(i=j=0 ; dest[i] != '\0'; i++) {
  3242.       if ( (gotquery && dest[i] == '&') || ( !gotquery && dest[i] == '?') ) {
  3243.         if (!gotquery) {
  3244.           gotquery=1;
  3245.           query = &dest[i];
  3246.           qLen = (int)strlen(query);
  3247.         }
  3248.         assertf(j < ampargs);
  3249.         amps[j++] = &dest[i];
  3250.         dest[i] = '\0';
  3251.       }
  3252.     }
  3253.     assertf(j == ampargs);
  3254.  
  3255.     /* Sort 'em all */
  3256.     qsort(amps, ampargs, sizeof(char*), sortNormFnc);
  3257.  
  3258.     /* Replace query by sorted query */
  3259.     copyBuff = malloct(qLen + 1);
  3260.     assertf(copyBuff != NULL);
  3261.     copyBuff[0] = '\0';
  3262.     for(i = 0 ; i < ampargs ; i++) {
  3263.       if (i == 0)
  3264.         strcatbuff(copyBuff, "?");
  3265.       else
  3266.         strcatbuff(copyBuff, "&");
  3267.       strcatbuff(copyBuff, amps[i] + 1);
  3268.     }
  3269.     assert((int)strlen(copyBuff) <= qLen);
  3270.     strcpybuff(query, copyBuff);
  3271.  
  3272.     /* Cleanup */
  3273.     freet(amps);
  3274.     freet(copyBuff);
  3275.   }
  3276.   
  3277.   return dest;
  3278. }
  3279.  
  3280. #define endwith(a) ( (len >= (sizeof(a)-1)) ? ( strncmp(dest, a+len-(sizeof(a)-1), sizeof(a)-1) == 0 ) : 0 );
  3281. HTSEXT_API char* adr_normalized(char* source, char* dest) {
  3282.   /* not yet too aggressive (no com<->net<->org checkings) */
  3283.   strcpybuff(dest, jump_normalized(source));
  3284.   return dest;
  3285. }
  3286. #undef endwith
  3287.  
  3288.  
  3289. // find port (:80) or NULL if not found
  3290. // can handle IPV6 addresses
  3291. HTSEXT_API char* jump_toport(char* source) {
  3292.   char *a,*trytofind;
  3293.   a = jump_identification(source);
  3294.   trytofind = strrchr_limit(a, ']', strchr(source, '/'));    // find last ] (http://[3ffe:b80:1234::1]:80/foo.html)
  3295.   a = strchr( (trytofind)?trytofind:a, ':');
  3296.   return a;
  3297. }
  3298.  
  3299. // strrchr, but not too far
  3300. char* strrchr_limit(char* s, char c, char* limit) {
  3301.   if (limit == NULL) {
  3302.     char* p = strrchr(s, c);
  3303.     return p?(p+1):NULL;
  3304.   } else {
  3305.     char *a=NULL, *p;
  3306.     for(;;) {
  3307.       p=strchr((a)?a:s, c);
  3308.       if ((p >= limit) || (p == NULL))
  3309.         return a;
  3310.       a=p+1;
  3311.     }
  3312.   }
  3313. }
  3314.  
  3315. // strrchr, but not too far
  3316. char* strstr_limit(char* s, char* sub, char* limit) {
  3317.   if (limit == NULL) {
  3318.     return strstr(s, sub);
  3319.   } else {
  3320.     char* pos = strstr(s, sub);
  3321.     if (pos != NULL) {
  3322.       char* farpos = strstr(s, limit);
  3323.       if (farpos == NULL || pos < farpos)
  3324.         return pos;
  3325.     }
  3326.   }
  3327.   return NULL;
  3328. }
  3329.  
  3330. // retourner adr sans ftp://
  3331. HTS_INLINE char* jump_protocol(char* source) {
  3332.   int p;
  3333.   // scheme
  3334.   // "Comparisons of scheme names MUST be case-insensitive" (RFC2616)
  3335.   if ((p=strfield(source,"http:")))
  3336.     source+=p;
  3337.   else if ((p=strfield(source,"ftp:")))
  3338.     source+=p;
  3339.   else if ((p=strfield(source,"https:")))
  3340.     source+=p;
  3341.   else if ((p=strfield(source,"file:")))
  3342.     source+=p;
  3343. #if HTS_USEMMS
  3344.   else if ((p=strfield(source,"mms:")))
  3345.     source+=p;
  3346. #endif
  3347.   // net_path
  3348.   if (strncmp(source,"//",2)==0)
  3349.     source+=2;
  3350.   return source;
  3351. }
  3352.  
  3353. // codage base 64 a vers b
  3354. void code64(unsigned char* a,int size_a,unsigned char* b,int crlf) {
  3355.   int i1=0,i2=0,i3=0,i4=0;
  3356.   int loop=0;
  3357.   unsigned long int store;
  3358.   int n;
  3359.   const char _hts_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  3360.   while(size_a-- > 0) {  
  3361.     // 24 bits
  3362.     n=1; 
  3363.     store = *a++;
  3364.     if (size_a-- > 0) { n=2; store <<= 8; store |= *a++; }
  3365.     if (size_a-- > 0) { n=3; store <<= 8; store |= *a++; }
  3366.     if (n==3) {
  3367.       i4=store & 63;
  3368.       i3=(store>>6) & 63;
  3369.       i2=(store>>12) & 63;
  3370.       i1=(store>>18) & 63;
  3371.     } else if (n==2) {
  3372.       store<<=2;    
  3373.       i3=store & 63;
  3374.       i2=(store>>6) & 63;
  3375.       i1=(store>>12) & 63;
  3376.     } else {
  3377.       store<<=4;
  3378.       i2=store & 63;
  3379.       i1=(store>>6) & 63;
  3380.     }
  3381.     
  3382.     *b++ = _hts_base64[i1];
  3383.     *b++ = _hts_base64[i2];
  3384.     if (n>=2)
  3385.       *b++ = _hts_base64[i3];
  3386.     else
  3387.       *b++ = '=';
  3388.     if (n>=3)
  3389.       *b++ = _hts_base64[i4];
  3390.     else
  3391.       *b++ = '=';
  3392.  
  3393.     if (crlf && ( ( loop += 3 ) % 60) == 0 ) {
  3394.       *b++ = '\r';
  3395.       *b++ = '\n';
  3396.     }
  3397.   }
  3398.   *b++='\0';
  3399. }
  3400.  
  3401. // remplacer " par " etc..
  3402. // buffer MAX 1Ko
  3403. #define strcmpbeg(a, b) strncmp(a, b, strlen(b))
  3404. HTSEXT_API void unescape_amp(char* s) {
  3405.   while(*s) {
  3406.     if (*s=='&') {
  3407.       char* end=strchr(s,';');
  3408.       if ( end && (((int) (end - s)) <= 8) ) {
  3409.         unsigned char c=0;
  3410.         
  3411.         // http://www.w3.org/TR/xhtml-modularization/dtd_module_defs.html
  3412.         if (strcmpbeg(s, "&#") == 0) {
  3413.           int num=0;
  3414.           if ( (s[2] == 'x') || (s[2] == 'X')) {
  3415.             if (sscanf(s+3, "%x", &num) == 1) {
  3416.               c=(unsigned char)num;
  3417.             }
  3418.           } else {
  3419.             if (sscanf(s+2, "%d", &num) == 1) {
  3420.               c=(unsigned char)num;
  3421.             }
  3422.           }
  3423.         } else if (strcmpbeg(s, " ")==0)
  3424.           c=32; // hack - c=160;
  3425.         else if (strcmpbeg(s, "¡")==0)
  3426.           c=161;
  3427.         else if (strcmpbeg(s, "¢")==0)
  3428.           c=162;
  3429.         else if (strcmpbeg(s, "£")==0)
  3430.           c=163;
  3431.         else if (strcmpbeg(s, "¤")==0)
  3432.           c=164;
  3433.         else if (strcmpbeg(s, "¥")==0)
  3434.           c=165;
  3435.         else if (strcmpbeg(s, "¦")==0)
  3436.           c=166;
  3437.         else if (strcmpbeg(s, "§")==0)
  3438.           c=167;
  3439.         else if (strcmpbeg(s, "¨")==0)
  3440.           c=168;
  3441.         else if (strcmpbeg(s, "©")==0)
  3442.           c=169;
  3443.         else if (strcmpbeg(s, "ª")==0)
  3444.           c=170;
  3445.         //else if (strcmpbeg(s, "«")==0)
  3446.         //  c=171;
  3447.         else if (strcmpbeg(s, "¬")==0)
  3448.           c=172;
  3449.         //else if (strcmpbeg(s, "­")==0)
  3450.         //  c=173;
  3451.         else if (strcmpbeg(s, "®")==0)
  3452.           c=174;
  3453.         else if (strcmpbeg(s, "¯")==0)
  3454.           c=175;
  3455.         else if (strcmpbeg(s, "°")==0)
  3456.           c=176;
  3457.         else if (strcmpbeg(s, "±")==0)
  3458.           c=177;
  3459.         else if (strcmpbeg(s, "²")==0)
  3460.           c=178;
  3461.         else if (strcmpbeg(s, "³")==0)
  3462.           c=179;
  3463.         else if (strcmpbeg(s, "´")==0)
  3464.           c=180;
  3465.         else if (strcmpbeg(s, "µ")==0)
  3466.           c=181;
  3467.         else if (strcmpbeg(s, "¶")==0)
  3468.           c=182;
  3469.         else if (strcmpbeg(s, "·")==0)
  3470.           c=183;
  3471.         else if (strcmpbeg(s, "¸")==0)
  3472.           c=184;
  3473.         else if (strcmpbeg(s, "¹")==0)
  3474.           c=185;
  3475.         else if (strcmpbeg(s, "º")==0)
  3476.           c=186;
  3477.         //else if (strcmpbeg(s, "»")==0)
  3478.         //  c=187;
  3479.         else if (strcmpbeg(s, "¼")==0)
  3480.           c=188;
  3481.         else if (strcmpbeg(s, "½")==0)
  3482.           c=189;
  3483.         else if (strcmpbeg(s, "¾")==0)
  3484.           c=190;
  3485.         else if (strcmpbeg(s, "¿")==0)
  3486.           c=191;
  3487.         else if (strcmpbeg(s, "À")==0)
  3488.           c=192;
  3489.         else if (strcmpbeg(s, "Á")==0)
  3490.           c=193;
  3491.         else if (strcmpbeg(s, "Â")==0)
  3492.           c=194;
  3493.         else if (strcmpbeg(s, "Ã")==0)
  3494.           c=195;
  3495.         else if (strcmpbeg(s, "Ä")==0)
  3496.           c=196;
  3497.         else if (strcmpbeg(s, "Å")==0)
  3498.           c=197;
  3499.         else if (strcmpbeg(s, "Æ")==0)
  3500.           c=198;
  3501.         else if (strcmpbeg(s, "Ç")==0)
  3502.           c=199;
  3503.         else if (strcmpbeg(s, "È")==0)
  3504.           c=200;
  3505.         else if (strcmpbeg(s, "É")==0)
  3506.           c=201;
  3507.         else if (strcmpbeg(s, "Ê")==0)
  3508.           c=202;
  3509.         else if (strcmpbeg(s, "Ë")==0)
  3510.           c=203;
  3511.         else if (strcmpbeg(s, "Ì")==0)
  3512.           c=204;
  3513.         else if (strcmpbeg(s, "Í")==0)
  3514.           c=205;
  3515.         else if (strcmpbeg(s, "Î")==0)
  3516.           c=206;
  3517.         else if (strcmpbeg(s, "Ï")==0)
  3518.           c=207;
  3519.         else if (strcmpbeg(s, "Ð")==0)
  3520.           c=208;
  3521.         else if (strcmpbeg(s, "Ñ")==0)
  3522.           c=209;
  3523.         else if (strcmpbeg(s, "Ò")==0)
  3524.           c=210;
  3525.         else if (strcmpbeg(s, "Ó")==0)
  3526.           c=211;
  3527.         else if (strcmpbeg(s, "Ô")==0)
  3528.           c=212;
  3529.         else if (strcmpbeg(s, "Õ")==0)
  3530.           c=213;
  3531.         else if (strcmpbeg(s, "Ö")==0)
  3532.           c=214;
  3533.         else if (strcmpbeg(s, "×")==0)
  3534.           c=215;
  3535.         else if (strcmpbeg(s, "Ø")==0)
  3536.           c=216;
  3537.         else if (strcmpbeg(s, "Ù")==0)
  3538.           c=217;
  3539.         else if (strcmpbeg(s, "Ú")==0)
  3540.           c=218;
  3541.         else if (strcmpbeg(s, "Û")==0)
  3542.           c=219;
  3543.         else if (strcmpbeg(s, "Ü")==0)
  3544.           c=220;
  3545.         else if (strcmpbeg(s, "Ý")==0)
  3546.           c=221;
  3547.         else if (strcmpbeg(s, "Þ")==0)
  3548.           c=222;
  3549.         else if (strcmpbeg(s, "ß")==0)
  3550.           c=223;
  3551.         else if (strcmpbeg(s, "à")==0)
  3552.           c=224;
  3553.         else if (strcmpbeg(s, "á")==0)
  3554.           c=225;
  3555.         else if (strcmpbeg(s, "â")==0)
  3556.           c=226;
  3557.         else if (strcmpbeg(s, "ã")==0)
  3558.           c=227;
  3559.         else if (strcmpbeg(s, "ä")==0)
  3560.           c=228;
  3561.         else if (strcmpbeg(s, "å")==0)
  3562.           c=229;
  3563.         else if (strcmpbeg(s, "æ")==0)
  3564.           c=230;
  3565.         else if (strcmpbeg(s, "ç")==0)
  3566.           c=231;
  3567.         else if (strcmpbeg(s, "è")==0)
  3568.           c=232;
  3569.         else if (strcmpbeg(s, "é")==0)
  3570.           c=233;
  3571.         else if (strcmpbeg(s, "ê")==0)
  3572.           c=234;
  3573.         else if (strcmpbeg(s, "ë")==0)
  3574.           c=235;
  3575.         else if (strcmpbeg(s, "ì")==0)
  3576.           c=236;
  3577.         else if (strcmpbeg(s, "í")==0)
  3578.           c=237;
  3579.         else if (strcmpbeg(s, "î")==0)
  3580.           c=238;
  3581.         else if (strcmpbeg(s, "ï")==0)
  3582.           c=239;
  3583.         else if (strcmpbeg(s, "ð")==0)
  3584.           c=240;
  3585.         else if (strcmpbeg(s, "ñ")==0)
  3586.           c=241;
  3587.         else if (strcmpbeg(s, "ò")==0)
  3588.           c=242;
  3589.         else if (strcmpbeg(s, "ó")==0)
  3590.           c=243;
  3591.         else if (strcmpbeg(s, "ô")==0)
  3592.           c=244;
  3593.         else if (strcmpbeg(s, "õ")==0)
  3594.           c=245;
  3595.         else if (strcmpbeg(s, "ö")==0)
  3596.           c=246;
  3597.         else if (strcmpbeg(s, "÷")==0)
  3598.           c=247;
  3599.         else if (strcmpbeg(s, "ø")==0)
  3600.           c=248;
  3601.         else if (strcmpbeg(s, "ù")==0)
  3602.           c=249;
  3603.         else if (strcmpbeg(s, "ú")==0)
  3604.           c=250;
  3605.         else if (strcmpbeg(s, "û")==0)
  3606.           c=251;
  3607.         else if (strcmpbeg(s, "ü")==0)
  3608.           c=252;
  3609.         else if (strcmpbeg(s, "ý")==0)
  3610.           c=253;
  3611.         else if (strcmpbeg(s, "þ")==0)
  3612.           c=254;
  3613.         else if (strcmpbeg(s, "ÿ")==0)
  3614.           c=255;
  3615.         //        
  3616.         else if (strcmpbeg(s,"&")==0)
  3617.           c='&';
  3618.         else if (strcmpbeg(s,">")==0)
  3619.           c='>';
  3620.         else if (strcmpbeg(s,"«")==0)
  3621.           c='\"';
  3622.         else if (strcmpbeg(s,"<")==0)
  3623.           c='<';
  3624.         else if (strcmpbeg(s," ")==0)
  3625.           c=' ';
  3626.         else if (strcmpbeg(s,""")==0)
  3627.           c='\"';
  3628.         else if (strcmpbeg(s,"»")==0)
  3629.           c='\"';
  3630.         else if (strcmpbeg(s,"­")==0)
  3631.           c='-';
  3632.         else if (strcmpbeg(s,"˜")==0)
  3633.           c='~';
  3634.         // remplacer?
  3635.         if (c) {
  3636.           char BIGSTK buff[HTS_URLMAXSIZE*2];
  3637.           buff[0]=(char) c;
  3638.           strcpybuff(buff+1,end+1);
  3639.           strcpybuff(s,buff);
  3640.         }
  3641.       }
  3642.     }
  3643.     s++;
  3644.   }
  3645. }
  3646.  
  3647. static int ehexh(char c) {
  3648.   if ((c>='0') && (c<='9')) return c-'0';
  3649.   if ((c>='a') && (c<='f')) c-=('a'-'A');
  3650.   if ((c>='A') && (c<='F')) return (c-'A'+10);
  3651.   return 0;
  3652. }
  3653.  
  3654. static int ehex(char* s) {
  3655.   return 16*ehexh(*s)+ehexh(*(s+1));
  3656. }
  3657.  
  3658. // remplacer %20 par ' ', | par : etc..
  3659. // buffer MAX 1Ko
  3660. HTSEXT_API char* unescape_http(char* s) {
  3661.   char* tempo;
  3662.   int i,j=0;
  3663.   NOSTATIC_RESERVE(tempo, char, HTS_URLMAXSIZE*2);
  3664.   for (i=0;i<(int) strlen(s);i++) {
  3665.     if (s[i]=='%') {
  3666.       i++;
  3667.       tempo[j++]=(char) ehex(s+i);
  3668.       i++;    // sauter 2 caractΦres finalement
  3669.     }
  3670.     /*
  3671.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  3672.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  3673.       tempo[j++]=':';
  3674.     }
  3675.     */
  3676.     else
  3677.       tempo[j++]=s[i];
  3678.   }
  3679.   tempo[j++]='\0';
  3680.   return tempo;
  3681. }
  3682.  
  3683. // unescape in URL/URI ONLY what has to be escaped, to form a standard URL/URI
  3684. // DOES NOT DECODE %25
  3685. HTSEXT_API char* unescape_http_unharm(char* s, int no_high) {
  3686.   char* tempo;
  3687.   int i,j=0;
  3688.   NOSTATIC_RESERVE(tempo, char, HTS_URLMAXSIZE*2);
  3689.   for (i=0;i<(int) strlen(s);i++) {
  3690.     if (s[i]=='%') {
  3691.       int nchar=(char) ehex(s+i+1);
  3692.  
  3693.       int test = (  CHAR_RESERVED(nchar)
  3694.                 || ( nchar != '%' && CHAR_DELIM(nchar) )
  3695.                 || CHAR_UNWISE(nchar)
  3696.                 || CHAR_LOW(nchar)        /* CHAR_SPECIAL */
  3697.                 || CHAR_XXAVOID(nchar) 
  3698.                 || (
  3699.                   (no_high)
  3700.                   &&
  3701.                   CHAR_HIG(nchar)
  3702.                 )
  3703.                 );
  3704.  
  3705.       if (!test) {
  3706.         tempo[j++]=(char) ehex(s+i+1);
  3707.         i+=2;
  3708.       } else {
  3709.         tempo[j++]='%';
  3710.       }
  3711.     }
  3712.     /*
  3713.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  3714.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  3715.       tempo[j++]=':';
  3716.     }
  3717.     */
  3718.     else
  3719.       tempo[j++]=s[i];
  3720.   }
  3721.   tempo[j++]='\0';
  3722.   return tempo;
  3723. }
  3724.  
  3725. // remplacer " par %xx etc..
  3726. // buffer MAX 1Ko
  3727. HTSEXT_API void escape_spc_url(char* s) {
  3728.   x_escape_http(s,2);
  3729. }
  3730. // smith / john -> smith%20%2f%20john
  3731. HTSEXT_API void escape_in_url(char* s) {
  3732.   x_escape_http(s,1);
  3733. }
  3734. // smith / john -> smith%20/%20john
  3735. HTSEXT_API void escape_uri(char* s) {
  3736.   x_escape_http(s,3);
  3737. }
  3738. HTSEXT_API void escape_uri_utf(char* s) {
  3739.   x_escape_http(s,30);
  3740. }
  3741. HTSEXT_API void escape_check_url(char* s) {
  3742.   x_escape_http(s,0);
  3743. }
  3744. // same as escape_check_url, but returns char*
  3745. HTSEXT_API char* escape_check_url_addr(char* s) {
  3746.   char* adr;
  3747.   escape_check_url(adr = concat(s,""));
  3748.   return adr;
  3749. }
  3750.  
  3751. // strip all control characters
  3752. HTSEXT_API void escape_remove_control(char* s) {
  3753.   unsigned char* ss = (unsigned char*) s;
  3754.   while(*ss) {
  3755.     if (*ss < 32) {    /* CONTROL characters go away! */
  3756.       char BIGSTK tmp[HTS_URLMAXSIZE*2];
  3757.       strcpybuff(tmp, ss+1);
  3758.       strcpybuff(ss, tmp);
  3759.     } else {
  3760.       ss++;
  3761.     }
  3762.   }
  3763. }
  3764.  
  3765. HTSEXT_API void x_escape_html(char* s) {
  3766.   while(*s) {
  3767.     int test=0;
  3768.       test = (
  3769.                 CHAR_HIG(*s)
  3770.              || CHAR_XXAVOID(*s) );
  3771.  
  3772.     if (test) {
  3773.       char BIGSTK buffer[HTS_URLMAXSIZE*3];
  3774.       int n;
  3775.       n = (int)(unsigned char) *s;
  3776.       strcpybuff(buffer, s+1);
  3777.       sprintf(s,"&#x%02x;", n);
  3778.       strcatbuff(s, buffer);
  3779.     }
  3780.     s++;
  3781.   }
  3782. }
  3783.  
  3784.  
  3785. HTSEXT_API void x_escape_http(char* s,int mode) {
  3786.   while(*s) {
  3787.     int test=0;
  3788.     if (mode == 0)
  3789.       test=(strchr("\" ",*s)!=0);
  3790.     else if (mode==1) {
  3791.       test = (  CHAR_RESERVED(*s)
  3792.              || CHAR_DELIM(*s)
  3793.              || CHAR_UNWISE(*s)
  3794.              || CHAR_SPECIAL(*s)
  3795.              || CHAR_XXAVOID(*s)
  3796.              || CHAR_MARK(*s));
  3797.     }
  3798.     else if (mode==2)
  3799.       test=(*s == ' ');           // n'escaper que espace
  3800.     else if (mode==3) {                   // Θchapper que ce qui est nΘcessaire
  3801.       test = (
  3802.                 CHAR_SPECIAL(*s)
  3803.              || CHAR_XXAVOID(*s) );
  3804.     }
  3805.     else if (mode==30) {                   // Θchapper que ce qui est nΘcessaire
  3806.       test = (
  3807.                 CHAR_LOW(*s)
  3808.              || CHAR_XXAVOID(*s) );
  3809.     }
  3810.  
  3811.     if (test) {
  3812.       char BIGSTK buffer[HTS_URLMAXSIZE*3];
  3813.       int n;
  3814.       n=(int)(unsigned char) *s;
  3815.       strcpybuff(buffer,s+1);
  3816.       sprintf(s,"%%%02x",n);
  3817.       strcatbuff(s,buffer);
  3818.     }
  3819.     s++;
  3820.   }
  3821. }
  3822.  
  3823. HTSEXT_API void escape_for_html_print(char* s, char* d) {
  3824.   for( ; *s ; s++) {
  3825.     if (*s == '&') {
  3826.       strcpybuff(d, "&");
  3827.       d += strlen(d);
  3828.     } else {
  3829.       *d++ = *s;
  3830.     }
  3831.   }
  3832.   *d = '\0';
  3833. }
  3834.  
  3835. HTSEXT_API void escape_for_html_print_full(char* s, char* d) {
  3836.   for( ; *s ; s++) {
  3837.     if (*s == '&') {
  3838.       strcpybuff(d, "&");
  3839.       d += strlen(d);
  3840.     } else if (CHAR_HIG(*s)) {
  3841.       sprintf(d, "&#x%02x;", (unsigned char) *s);
  3842.       d += strlen(d);
  3843.     } else {
  3844.       *d++ = *s;
  3845.     }
  3846.   }
  3847.   *d = '\0';
  3848. }
  3849.  
  3850.  
  3851.  
  3852. // concat, concatΦne deux chaines et renvoi le rΘsultat
  3853. // permet d'allΘger grandement le code
  3854. // il faut savoir qu'on ne peut mettre plus de 16 concat() dans une expression
  3855. typedef struct {
  3856.   char buff[16][HTS_URLMAXSIZE*2*2];
  3857.   int rol;
  3858. } concat_strc;
  3859. char* concat(const char* a,const char* b) {
  3860.   concat_strc* strc;
  3861.   NOSTATIC_RESERVE(strc, concat_strc, 1);
  3862.   strc->rol=((strc->rol+1)%16);    // roving pointer
  3863.   strcpybuff(strc->buff[strc->rol],a);
  3864.   if (b) strcatbuff(strc->buff[strc->rol],b);
  3865.   return strc->buff[strc->rol];
  3866. }
  3867. // conversion fichier / -> antislash
  3868. #if HTS_DOSNAME
  3869. char* __fconv(char* a) {
  3870.   int i;
  3871.   for(i=0;i<(int) strlen(a);i++)
  3872.     if (a[i]=='/')  // convertir
  3873.       a[i]='\\';
  3874.   return a;
  3875. }
  3876. char* fconcat(char* a,char* b) {
  3877.   return __fconv(concat(a,b));
  3878. }
  3879. char* fconv(char* a) {
  3880.   return __fconv(concat(a,""));
  3881. }
  3882. #endif
  3883.  
  3884. /* / et \\ en / */
  3885. char* __fslash(char* a) {
  3886.   int i;
  3887.   for(i=0;i<(int) strlen(a);i++)
  3888.     if (a[i]=='\\')  // convertir
  3889.       a[i]='/';
  3890.   return a;
  3891. }
  3892. char* fslash(char* a) {
  3893.   return __fslash(concat(a,""));
  3894. }
  3895.  
  3896. // conversion minuscules, avec buffer
  3897. char* convtolower(char* a) {
  3898.   concat_strc* strc;
  3899.   NOSTATIC_RESERVE(strc, concat_strc, 1);
  3900.   strc->rol=((strc->rol+1)%16);    // roving pointer
  3901.   strcpybuff(strc->buff[strc->rol],a);
  3902.   hts_lowcase(strc->buff[strc->rol]);  // lower case
  3903.   return strc->buff[strc->rol];
  3904. }
  3905.  
  3906. // conversion en minuscules
  3907. void hts_lowcase(char* s) {
  3908.   int i;
  3909.   for(i=0;i<(int) strlen(s);i++)
  3910.     if ((s[i]>='A') && (s[i]<='Z'))
  3911.       s[i]+=('a'-'A');
  3912. }
  3913.  
  3914. // remplacer un caractΦre d'une chaεne dans une autre
  3915. HTS_INLINE void hts_replace(char *s,char from,char to) { 
  3916.   char* a;
  3917.   while ((a=strchr(s,from))!=NULL) {
  3918.     *a=to;
  3919.   }
  3920. }
  3921.  
  3922.  
  3923. // caractΦre espace, guillemets, CR, LF etc..
  3924. /* SECTION OPTIMISEE:
  3925.   #define  is_space(c) (strchr(" \"\x0d\x0a\x09'",c)!=NULL)
  3926.   #define  is_realspace(c) (strchr(" \x0d\x0a\x09\x0c",c)!=NULL)
  3927. */
  3928. /*
  3929. HTS_INLINE int is_space(char c) {
  3930.   if (c==' ')  return 1;  // spc
  3931.   if (c=='"')  return 1;  // quote
  3932.   if (c==10)   return 1;  // lf
  3933.   if (c==13)   return 1;  // cr
  3934.   if (c=='\'') return 1;  // quote
  3935.   //if (c=='`')  return 1;  // backquote      << non
  3936.   if (c==9)    return 1;  // tab
  3937.   return 0;
  3938. }
  3939. */
  3940.  
  3941. // caractΦre espace, CR, LF, TAB
  3942. /*
  3943. HTS_INLINE int is_realspace(char c) {
  3944.   if (c==' ')  return 1;  // spc
  3945.   if (c==10)   return 1;  // lf
  3946.   if (c==13)   return 1;  // cr
  3947.   if (c==9)    return 1;  // tab
  3948.   return 0;
  3949. }
  3950. */
  3951.  
  3952.  
  3953.  
  3954.  
  3955.  
  3956. // deviner type d'un fichier local..
  3957. // ex: fil="toto.gif" -> s="image/gif"
  3958. void guess_httptype(char *s,const char *fil) {
  3959.   get_httptype(s, fil, 1);
  3960. }
  3961. // idem
  3962. // flag: 1 si toujours renvoyer un type
  3963. void get_httptype(char *s,const char *fil,int flag) {
  3964.   // userdef overrides get_httptype
  3965.   if (get_userhttptype(0, s, fil)) {
  3966.     return ;
  3967.   }
  3968.   // regular tests
  3969.   if (ishtml(fil) == 1) {
  3970.     strcpybuff(s,"text/html");
  3971.   } else {
  3972.     /* Check html -> text/html */
  3973.     const char* a = fil + strlen(fil) - 1;    
  3974.     while ( (*a!='.') && (*a!='/') && (a>fil)) a--;
  3975.     if (*a=='.' && strlen(a) < 32) {
  3976.       int j=0;
  3977.       a++;
  3978.       while(strnotempty(hts_mime[j][1])) {
  3979.         if (strfield2(hts_mime[j][1],a)) {
  3980.           if (hts_mime[j][0][0]!='*') {    // Une correspondance existe
  3981.             strcpybuff(s,hts_mime[j][0]);
  3982.             return;
  3983.           }
  3984.         }
  3985.         j++;
  3986.       }
  3987.       
  3988.       if (flag)
  3989.         sprintf(s,"application/%s",a);
  3990.     } else {
  3991.       if (flag)
  3992.         strcpybuff(s,"application/octet-stream");
  3993.     }
  3994.   }
  3995. }
  3996.  
  3997. // get type of fil (php)
  3998. // s: buffer (text/html) or NULL
  3999. // return: 1 if known by user
  4000. int get_userhttptype(int setdefs, char *s, const char *fil) {
  4001.   char** buffer=NULL;
  4002.   NOSTATIC_RESERVE(buffer, char*, 1);
  4003.   if (setdefs) {
  4004.     *buffer=s;
  4005.     return 1;
  4006.   } else {
  4007.     if (s)
  4008.       s[0]='\0';
  4009.     if (fil == NULL || *fil == '\0')
  4010.       return 0;
  4011. #if 1
  4012.     if (*buffer) {
  4013.  
  4014.       /* Check --assume foooo/foo/bar.cgi=text/html, then foo/bar.cgi=text/html, then bar.cgi=text/html */
  4015.       /* also: --assume baz,bar,foooo/foo/bar.cgi=text/html */
  4016.       /* start from path begining */
  4017.       do {
  4018.         char* next;
  4019.         char* mimedefs = *buffer;    /* loop through mime definitions : \nfoo=bar\nzoo=baz\n.. */
  4020.         while(*mimedefs != '\0') {
  4021.           const char* segment = fil + 1;
  4022.           if (*mimedefs == '\n') {
  4023.             mimedefs++;
  4024.           }
  4025.           /* compare current segment with user's definition */
  4026.           do {
  4027.             int i;
  4028.             /* check current item */
  4029.             for(i = 0 ; 
  4030.               mimedefs[i] != '\0'           /* end of all defs */
  4031.               && mimedefs[i] != ' '         /* next item in left list */
  4032.               && mimedefs[i] != '='         /* end of left list */
  4033.               && mimedefs[i] != '\n'        /* end of this def (?) */
  4034.               && mimedefs[i] == segment[i]  /* same item */
  4035.               ; i++);
  4036.             /* success */
  4037.             if ( ( mimedefs[i] == '=' || mimedefs[i] == ' ' ) && segment[i] == '\0') {
  4038.               int i2;
  4039.               while(mimedefs[i] != 0 && mimedefs[i] != '\n' && mimedefs[i] != '=') i++;
  4040.               if (mimedefs[i] == '=') {
  4041.                 i++;
  4042.                 for(i2 = 0 ; mimedefs[i + i2] != '\n' && mimedefs[i + i2] != '\0' ; i2++) {
  4043.                   s[i2] = mimedefs[i + i2];
  4044.                 }
  4045.                 s[i2] = '\0';
  4046.                 return 1;   /* SUCCESS! */
  4047.               }
  4048.             }
  4049.             /* next item in list */
  4050.             for(mimedefs += i ; 
  4051.               *mimedefs != '\0' && *mimedefs != '\n' && *mimedefs != '=' && *mimedefs != ' ' ; 
  4052.               mimedefs++);
  4053.             if (*mimedefs == ' ') {
  4054.               mimedefs++;
  4055.             }
  4056.           } while(*mimedefs != '\0' && *mimedefs != '\n' && *mimedefs != '=');
  4057.           /* next user-def */
  4058.           for( ; *mimedefs != '\0' && *mimedefs != '\n' ; mimedefs++);
  4059.         }
  4060.         /* shorten segment */
  4061.         next = strchr(fil + 1, '/');
  4062.         if (next == NULL) {
  4063.           /* ext tests */
  4064.           next = strchr(fil + 1, '.');
  4065.         }
  4066.         fil = next;
  4067.       } while(fil != NULL);
  4068.     }
  4069. #else
  4070.     if (*buffer) {
  4071.       char BIGSTK search[1024];
  4072.       char* detect;
  4073.  
  4074.  
  4075.       sprintf(search,"\n%s=",ext);    // php=text/html
  4076.       detect=strstr(*buffer,search);
  4077.       if (!detect) {
  4078.         sprintf(search,"\n%s\n",ext); // php\ncgi=text/html
  4079.         detect=strstr(*buffer,search);
  4080.       }
  4081.       if (detect) {
  4082.         detect=strchr(detect,'=');
  4083.         if (detect) {
  4084.           detect++;
  4085.           if (s) {
  4086.             char* a;
  4087.             a=strchr(detect,'\n');
  4088.             if (a) {
  4089.               strncatbuff(s,detect,(int) (a - detect));
  4090.             }
  4091.           }
  4092.           return 1;
  4093.         }
  4094.       }
  4095.     }
  4096. #endif
  4097.   }
  4098.   return 0;
  4099. }
  4100. // renvoyer extesion d'un type mime..
  4101. // ex: "image/gif" -> gif
  4102. void give_mimext(char *s,const char *st) {   
  4103.   int ok=0;
  4104.   int j=0;
  4105.   s[0]='\0';
  4106.   while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  4107.     if (strfield2(hts_mime[j][0],st)) {
  4108.       if (hts_mime[j][1][0]!='*') {    // Une correspondance existe
  4109.         strcpybuff(s,hts_mime[j][1]);
  4110.         ok=1;
  4111.       }
  4112.     }
  4113.     j++;
  4114.   }
  4115.   // wrap "x" mimetypes, such as:
  4116.   // application/x-mp3
  4117.   // or
  4118.   // application/mp3
  4119.   if (!ok) {
  4120.     int p;
  4121.     const char* a=NULL;
  4122.     if ((p=strfield(st,"application/x-")))
  4123.       a=st+p;
  4124.     else if ((p=strfield(st,"application/")))
  4125.       a=st+p;
  4126.     if (a) {
  4127.       if ((int)strlen(a) >= 1) {
  4128.         if ((int)strlen(a) <= 4) {
  4129.           strcpybuff(s,a);
  4130.           ok=1;
  4131.         }
  4132.       }
  4133.     }
  4134.   }
  4135. }
  4136. // extension connue?..
  4137. //  0 : non
  4138. //  1 : oui
  4139. //  2 : html
  4140. int is_knowntype(const char *fil) {
  4141.   const char *ext;
  4142.   int j=0;
  4143.   if (!fil)
  4144.     return 0;
  4145.   ext = get_ext(fil);
  4146.   while(strnotempty(hts_mime[j][1])) {
  4147.     if (strfield2(hts_mime[j][1], ext)) {
  4148.       if (strfield2(hts_mime[j][0], "text/html"))
  4149.         return 2;
  4150.       else
  4151.         return 1;
  4152.     }
  4153.     j++;
  4154.   }
  4155.  
  4156.   // Known by user?
  4157.   return (is_userknowntype(fil));
  4158. }
  4159. // extension : html,gif..
  4160. char* get_ext(const char *fil) {
  4161.   char* fil_noquery;
  4162.   const char *a=fil+strlen(fil)-1;    
  4163.   NOSTATIC_RESERVE(fil_noquery, char, HTS_URLMAXSIZE*2);
  4164.  
  4165.   while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  4166.   if (*a=='.') {
  4167.     char* b;
  4168.     fil_noquery[0]='\0';
  4169.     a++;  // pointer sur extension
  4170.     strncatbuff(fil_noquery,a,HTS_URLMAXSIZE);
  4171.     b=strchr(fil_noquery,'?');
  4172.     if (b)
  4173.       *b='\0';
  4174.     return concat(fil_noquery,"");
  4175.   }
  4176.   else
  4177.     return "";
  4178. }
  4179. // known type?..
  4180. //  0 : no
  4181. //  1 : yes
  4182. //  2 : html
  4183. // setdefs : set mime buffer:
  4184. //   file=(char*) "asp=text/html\nphp=text/html\n"
  4185. int is_userknowntype(const char *fil) {
  4186.   char BIGSTK mime[1024];
  4187.   if (!fil)
  4188.     return 0;
  4189.   if (!strnotempty(fil))
  4190.     return 0;
  4191.   mime[0]='\0';
  4192.   get_userhttptype(0,mime,fil);
  4193.   if (!strnotempty(mime))
  4194.     return 0;
  4195.   else if (strfield2(mime,"text/html"))
  4196.     return 2;
  4197.   else
  4198.     return 1;
  4199. }
  4200.  
  4201. // page dynamique?
  4202. // is_dyntype(get_ext("foo.asp"))
  4203. int is_dyntype(const char *fil) {
  4204.   int j=0;
  4205.   if (!fil)
  4206.     return 0;
  4207.   if (!strnotempty(fil))
  4208.     return 0;
  4209.   while(strnotempty(hts_ext_dynamic[j])) {
  4210.     if (strfield2(hts_ext_dynamic[j],fil)) {
  4211.       return 1;
  4212.     }
  4213.     j++;
  4214.   }
  4215.   return 0;
  4216. }
  4217.  
  4218. // types critiques qui ne doivent pas Ωtre changΘs car renvoyΘs par des serveurs qui ne
  4219. // connaissent pas le type
  4220. int may_unknown(const char* st) {
  4221.   int j=0;
  4222.   // types mΘdia
  4223.   if (may_be_hypertext_mime(st, "")) {
  4224.     return 1;
  4225.   }
  4226.   while(strnotempty(hts_mime_keep[j])) {
  4227.     if (strfield2(hts_mime_keep[j],st)) {      // trouvΘ
  4228.       return 1;
  4229.     }
  4230.     j++;
  4231.   }    
  4232.   return 0;
  4233. }
  4234.  
  4235.  
  4236. // -- Utils fichiers
  4237.  
  4238. // pretty print for i/o
  4239. void fprintfio(FILE* fp,char* buff,char* prefix) {
  4240.   char nl=1;
  4241.   while(*buff) {
  4242.     switch(*buff) {
  4243.     case 13: break;
  4244.     case 10:
  4245.       fprintf(fp,"\r\n");
  4246.       nl=1;
  4247.     break;
  4248.     default:
  4249.       if (nl)
  4250.         fprintf(fp,prefix);
  4251.       nl=0;
  4252.       fputc(*buff,fp);
  4253.     }
  4254.     buff++;
  4255.   }
  4256. }
  4257.  
  4258. /* Le fichier existe-t-il? (ou est-il accessible?) */
  4259. int fexist(char* s) {
  4260.   struct stat st;
  4261.   memset(&st, 0, sizeof(st));
  4262.   if (stat(s, &st) == 0) {
  4263.     if (S_ISREG(st.st_mode)) {
  4264.       return 1;
  4265.     }
  4266.   }
  4267.   return 0;
  4268.  
  4269. /* Taille d'un fichier, -1 si n'existe pas */
  4270. /* fp->_cnt ne fonctionne pas sur toute les plate-formes :-(( */
  4271. /* Note: NOT YET READY FOR 64-bit */
  4272. INTsys fsize(char* s) {
  4273.   FILE* fp;
  4274.   if (strnotempty(s)==0)     // nom vide: erreur
  4275.     return -1;
  4276.   fp=fopen(fconv(s),"rb");
  4277.   if (fp!=NULL) {
  4278.     INTsys i;
  4279.     fseek(fp,0,SEEK_END);
  4280. #ifdef HTS_FSEEKO
  4281.     i=ftello(fp);
  4282. #else
  4283.     i=ftell(fp);
  4284. #endif
  4285.     fclose(fp);
  4286.     return i;
  4287.   } else return -1;
  4288. }
  4289.  
  4290. INTsys fpsize(FILE* fp) {
  4291.   INTsys oldpos,size;
  4292.   if (!fp)
  4293.     return -1;
  4294. #ifdef HTS_FSEEKO
  4295.   oldpos=ftello(fp);
  4296. #else
  4297.   oldpos=ftell(fp);
  4298. #endif
  4299.   fseek(fp,0,SEEK_END);
  4300. #ifdef HTS_FSEEKO
  4301.   size=ftello(fp);
  4302.   fseeko(fp,oldpos,SEEK_SET);
  4303. #else
  4304.   size=ftell(fp);
  4305.   fseek(fp,oldpos,SEEK_SET);
  4306. #endif
  4307.   return size;
  4308. }
  4309.  
  4310. /* root dir, with ending / */
  4311. typedef struct {
  4312.   char path[1024+4];
  4313.   int init;
  4314. } hts_rootdir_strc;
  4315. HTSEXT_API char* hts_rootdir(char* file) {
  4316.   static hts_rootdir_strc strc = {"", 0};
  4317.   //NOSTATIC_RESERVE(strc, hts_rootdir_strc, 1);
  4318.   if (file) {
  4319.     if (!strc.init) {
  4320.       strc.path[0]='\0';
  4321.       strc.init=1;
  4322.       if (strnotempty(file)) {
  4323.         char* a;
  4324.         strcpybuff(strc.path,file);
  4325.         while((a=strrchr(strc.path,'\\'))) *a='/';
  4326.         if ((a=strrchr(strc.path,'/'))) {
  4327.           *(a+1)='\0';
  4328.         } else
  4329.           strc.path[0]='\0';
  4330.       }
  4331.       if (!strnotempty(strc.path)) {
  4332.         if( getcwd( strc.path, 1024 ) == NULL )
  4333.             strc.path[0]='\0';
  4334.         else
  4335.           strcatbuff(strc.path,"/");
  4336.       }
  4337.     }
  4338.     return NULL;
  4339.   } else if (strc.init)
  4340.     return strc.path;
  4341.   else
  4342.     return "";
  4343. }
  4344.  
  4345.  
  4346.  
  4347. HTSEXT_API hts_stat_struct HTS_STAT;
  4348. //
  4349. // return  number of downloadable bytes, depending on rate limiter
  4350. // see engine_stats() routine, too
  4351. // this routine works quite well for big files and regular ones, but apparently the rate limiter has
  4352. // some problems with very small files (rate too high)
  4353. LLint check_downloadable_bytes(int rate) {
  4354.   if (rate>0) {
  4355.     TStamp time_now;
  4356.     TStamp elapsed_useconds;
  4357.     LLint bytes_transfered_during_period;
  4358.     LLint left;
  4359.  
  4360.     // get the older timer
  4361.     int id_timer = (HTS_STAT.istat_idlasttimer + 1) % 2;
  4362.  
  4363.     time_now=mtime_local();
  4364.     elapsed_useconds = time_now - HTS_STAT.istat_timestart[id_timer];
  4365.     // NO totally stupid - elapsed_useconds+=1000;      // for the next second, too
  4366.     bytes_transfered_during_period = (HTS_STAT.HTS_TOTAL_RECV-HTS_STAT.istat_bytes[id_timer]);
  4367.     
  4368.     left = ((rate * elapsed_useconds)/1000) - bytes_transfered_during_period;
  4369.     if (left <= 0)
  4370.       left = 0;
  4371.     
  4372.     return left;
  4373.   } else
  4374.     return TAILLE_BUFFER;
  4375. }
  4376.  
  4377. //
  4378. // 0 : OK
  4379. // 1 : slow down
  4380. #if 0
  4381. int HTS_TOTAL_RECV_CHECK(int var) {
  4382.   if (HTS_STAT.HTS_TOTAL_RECV_STATE)
  4383.     return 1;
  4384.     /*
  4385.     {
  4386.     if (HTS_STAT.HTS_TOTAL_RECV_STATE==3) { 
  4387.       var = min(var,32); 
  4388.       Sleep(250); 
  4389.     } else if (HTS_STAT.HTS_TOTAL_RECV_STATE==2) { 
  4390.       var = min(var,256); 
  4391.       Sleep(100); 
  4392.     } else { 
  4393.       var/=2; 
  4394.       if (var<=0) var=1; 
  4395.       Sleep(50); 
  4396.     } 
  4397.   }
  4398.     */
  4399.   return 0;
  4400. }
  4401. #endif
  4402.  
  4403. // Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
  4404. // returns: 
  4405. // >0 : data received
  4406. // == 0 : not yet data
  4407. // <0: error or no data: READ_ERROR, READ_EOF or READ_TIMEOUT
  4408. HTS_INLINE int hts_read(htsblk* r,char* buff,int size) {
  4409.   int retour;
  4410.   //  return read(soc,buff,size);
  4411.   if (r->is_file) {
  4412. #if HTS_WIDE_DEBUG    
  4413.     DEBUG_W("read(%p, %d, %d)\n" _ (void*) buff _ (int) size _ (int) r->fp);
  4414. #endif
  4415.     if (r->fp)
  4416.       retour = (int)fread(buff,1,size,r->fp);
  4417.     else
  4418.       retour = READ_ERROR;
  4419.   } else {
  4420. #if HTS_WIDE_DEBUG    
  4421.     DEBUG_W("recv(%d, %p, %d)\n" _ (int) r->soc _ (void*) buff _ (int) size);
  4422.     if (r->soc==INVALID_SOCKET)
  4423.       printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
  4424. #endif
  4425.     //HTS_TOTAL_RECV_CHECK(size);         // Diminuer au besoin si trop de donnΘes reτues
  4426. #if HTS_USEOPENSSL
  4427.     if (SSL_is_available && r->ssl) {
  4428.       retour = SSL_read(r->ssl_con, buff, size);
  4429.       if (retour <= 0) {
  4430.         int err_code = SSL_get_error(r->ssl_con, retour);
  4431.         if (
  4432.           (err_code == SSL_ERROR_WANT_READ)
  4433.           ||
  4434.           (err_code == SSL_ERROR_WANT_WRITE)
  4435.           ) 
  4436.         {
  4437.           retour = 0;             /* no data yet (ssl cache) */
  4438.         } else if (err_code == SSL_ERROR_ZERO_RETURN) {
  4439.           retour = READ_EOF;             /* completed */
  4440.         } else {
  4441.           retour = READ_ERROR;            /* eof or error */
  4442.         }
  4443.       }
  4444.     } else {
  4445. #endif
  4446.     retour=recv(r->soc,buff,size,0);
  4447.     if (retour == 0) {
  4448.       retour = READ_EOF;
  4449.     } else if (retour < 0) {
  4450.       retour = READ_ERROR;
  4451.     }
  4452.   }
  4453.   if (retour > 0)    // compter flux entrant
  4454.     HTS_STAT.HTS_TOTAL_RECV+=retour;
  4455. #if HTS_USEOPENSSL
  4456.   }
  4457. #endif
  4458. #if HTS_WIDE_DEBUG    
  4459.   DEBUG_W("recv/read done (%d bytes)\n" _ (int) retour);
  4460. #endif
  4461.   return retour;
  4462. }
  4463.  
  4464.  
  4465. // -- Gestion cache DNS --
  4466. // 'RX98
  4467. #if HTS_DNSCACHE
  4468.  
  4469. // 'capsule' contenant uniquement le cache
  4470. t_dnscache* _hts_cache(void) {
  4471.   t_dnscache* cache;
  4472.   NOSTATIC_RESERVE(cache, t_dnscache, 1);
  4473.   return cache;
  4474. }
  4475. // free the cache
  4476. static void hts_cache_free_(t_dnscache* cache) {
  4477.   if (cache != NULL) {
  4478.     if (cache->n != NULL) {
  4479.       hts_cache_free_(cache->n);
  4480.     }
  4481.     freet(cache);
  4482.   }
  4483. }
  4484. void hts_cache_free(t_dnscache* cache) {
  4485.   if (cache != NULL && cache->n != NULL) {
  4486.     hts_cache_free_(cache->n);
  4487.     cache->n = NULL;
  4488.   }
  4489. }
  4490.  
  4491. // lock le cache dns pour tout opΘration d'ajout
  4492. // plus prudent quand plusieurs threads peuvent Θcrire dedans..
  4493. // -1: status? 0: libΘrer 1:locker
  4494.  
  4495. /* 
  4496.   Simple lock function for cache
  4497.  
  4498.   Return value: always 0
  4499.   Parameter:
  4500.   1 wait for lock (mutex) available and lock it
  4501.   0 unlock the mutex
  4502.   [-1 check if locked (always return 0 with mutex)]
  4503.   -999 initialize
  4504. */
  4505. #if USE_BEGINTHREAD
  4506. int _hts_lockdns(int i) {
  4507.   static PTHREAD_LOCK_TYPE hMutex; 
  4508.   return htsSetLock(&hMutex,i);
  4509. }
  4510. #else
  4511. int _hts_lockdns(int i) {
  4512.   int l=0;
  4513.   if (i>=0)
  4514.     l=i;
  4515.   return l;
  4516. }
  4517. #endif
  4518.  
  4519. // routine pour le cache - retour optionnel α donner α chaque fois
  4520. // NULL: nom non encore testΘ dans le cache
  4521. // si h_length==0 alors le nom n'existe pas dans le dns
  4522. t_hostent* _hts_ghbn(t_dnscache* cache,char* iadr,t_hostent* retour) {
  4523.   // attendre que le cache dns soit prΩt
  4524.   //while(_hts_lockdns(-1));  // attendre libΘration
  4525.   _hts_lockdns(1);          // locker
  4526.  
  4527.   while(1) {
  4528.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  4529.       if (cache->host_length>0) {  // entrΘe valide
  4530.         if (retour->h_addr_list[0])
  4531.           memcpy(retour->h_addr_list[0], cache->host_addr, cache->host_length);
  4532.         retour->h_length=cache->host_length;
  4533.       } else if (cache->host_length==0) {  // en cours
  4534.         _hts_lockdns(0);          // dΘlocker
  4535.         return NULL;
  4536.       } else {                    // erreur dans le dns, dΘja vΘrifiΘ
  4537.         if (retour->h_addr_list[0])
  4538.           retour->h_addr_list[0][0]='\0';
  4539.         retour->h_length=0;  // erreur, n'existe pas
  4540.       }
  4541.       _hts_lockdns(0);          // dΘlocker
  4542.       return retour;
  4543.     } else {    // on a pas encore trouvΘ
  4544.       if (cache->n!=NULL) { // chercher encore
  4545.         cache=cache->n;   // suivant!
  4546.       } else {
  4547.         _hts_lockdns(0);          // dΘlocker
  4548.         return NULL;    // non prΘsent        
  4549.       }
  4550.     }    
  4551.   }
  4552. }
  4553.  
  4554. // tester si iadr a dΘja ΘtΘ testΘ (ou en cours de test)
  4555. // 0 non encore
  4556. // 1 ok
  4557. // 2 non prΘsent
  4558. int hts_dnstest(char* _iadr) {
  4559.   char* iadr;
  4560.   t_dnscache* cache=_hts_cache();  // adresse du cache 
  4561.   NOSTATIC_RESERVE(iadr, char, HTS_URLMAXSIZE*2);
  4562.  
  4563.   // sauter user:pass@ Θventuel
  4564.   strcpybuff(iadr,jump_identification(_iadr));
  4565.   // couper Θventuel :
  4566.   {
  4567.     char *a;
  4568.     if ( (a=jump_toport(iadr)) )
  4569.       *a='\0';
  4570.   }
  4571.  
  4572. #if HTS_WIN
  4573.   if (inet_addr(iadr)!=INADDR_NONE)  // numΘrique
  4574. #else
  4575.   if (inet_addr(iadr)!=(in_addr_t) -1 )  // numΘrique
  4576. #endif
  4577.     return 1;
  4578.  
  4579.   // while(_hts_lockdns(-1));  // attendre libΘration
  4580.   _hts_lockdns(1);          // locker
  4581.   while(1) {
  4582.     if (strcmp(cache->iadr,iadr)==0) {  // ok trouvΘ
  4583.       _hts_lockdns(0);          // dΘlocker
  4584.       return 1;    // prΘsent!
  4585.     } else {    // on a pas encore trouvΘ
  4586.       if (cache->n!=NULL) { // chercher encore
  4587.         cache=cache->n;   // suivant!
  4588.       } else {
  4589.         _hts_lockdns(0);          // dΘlocker
  4590.         return 2;    // non prΘsent        
  4591.       }
  4592.     }    
  4593.   }
  4594. }
  4595.  
  4596.  
  4597. HTSEXT_API t_hostent* vxgethostbyname(char* hostname, void* v_buffer) {
  4598.   t_fullhostent* buffer = (t_fullhostent*) v_buffer;
  4599.   /* Clear */
  4600.   fullhostent_init(buffer);
  4601.  
  4602.   /* Protection */
  4603.   if (!strnotempty(hostname)) {
  4604.     return NULL;
  4605.   }
  4606.  
  4607.   /* 
  4608.     Strip [] if any : [3ffe:b80:1234:1::1] 
  4609.     The resolver doesn't seem to handle IP6 addresses in brackets
  4610.   */
  4611.   if ((hostname[0] == '[') && (hostname[strlen(hostname)-1] == ']')) {
  4612.     char BIGSTK tempo[HTS_URLMAXSIZE*2];
  4613.     tempo[0]='\0';
  4614.     strncatbuff(tempo, hostname+1, strlen(hostname)-2);
  4615.     strcpybuff(hostname, tempo);
  4616.   }
  4617.  
  4618.   {
  4619. #if HTS_INET6==0
  4620.   /*
  4621.   ipV4 resolver
  4622.     */
  4623.     t_hostent* hp=gethostbyname(hostname);
  4624.     if (hp!=NULL) {
  4625.       if ( (hp->h_length) && ( ((unsigned int) hp->h_length) <= buffer->addr_maxlen) ) {
  4626.         memcpy(buffer->hp.h_addr_list[0], hp->h_addr_list[0], hp->h_length);
  4627.         buffer->hp.h_length = hp->h_length;
  4628.         return &(buffer->hp);
  4629.       }
  4630.     }
  4631. #else
  4632.     /*
  4633.     ipV6 resolver
  4634.     */
  4635.     /*
  4636.     int error_num=0;
  4637.     t_hostent* hp=getipnodebyname(hostname, AF_INET6, AI_DEFAULT, &error_num);
  4638.     oops, deprecated :(
  4639.     */
  4640.     struct addrinfo* res = NULL;
  4641.     struct addrinfo hints;
  4642.     memset(&hints, 0, sizeof(hints));
  4643.     if (IPV6_resolver == 1)        // V4 only (for bogus V6 entries)
  4644.       hints.ai_family = PF_INET;
  4645.     else if (IPV6_resolver == 2)   // V6 only (for testing V6 only)
  4646.       hints.ai_family = PF_INET6;
  4647.     else                           // V4 + V6
  4648.       hints.ai_family = PF_UNSPEC;
  4649.     hints.ai_socktype = SOCK_STREAM;
  4650.     hints.ai_protocol = IPPROTO_TCP;
  4651.     if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
  4652.       if (res) {
  4653.         if ( (res->ai_addr) && (res->ai_addrlen) && (res->ai_addrlen <= buffer->addr_maxlen) ) {
  4654.           memcpy(buffer->hp.h_addr_list[0], res->ai_addr, res->ai_addrlen);
  4655.           buffer->hp.h_length = res->ai_addrlen;
  4656.           freeaddrinfo(res);
  4657.           return &(buffer->hp);
  4658.         }
  4659.       }
  4660.     }
  4661.     if (res) {
  4662.       freeaddrinfo(res);
  4663.     }
  4664.     
  4665. #endif
  4666.   }
  4667.   return NULL;
  4668. }
  4669.  
  4670. // cache dns interne α HTS // ** FREE A FAIRE sur la chaine
  4671. t_hostent* hts_gethostbyname(char* _iadr, void* v_buffer) {
  4672.   char BIGSTK iadr[HTS_URLMAXSIZE*2];
  4673.   t_fullhostent* buffer = (t_fullhostent*) v_buffer;
  4674.   t_dnscache* cache=_hts_cache();  // adresse du cache
  4675.   t_hostent* hp;
  4676.  
  4677.   /* Clear */
  4678.   fullhostent_init(buffer);
  4679.  
  4680.   strcpybuff(iadr,jump_identification(_iadr));
  4681.   // couper Θventuel :
  4682.   {
  4683.     char *a;
  4684.     if ( (a=jump_toport(iadr)) )
  4685.       *a='\0';
  4686.   }
  4687.  
  4688.   // effacer structure de retour, crΘer nouvelle
  4689.   /*
  4690.   memset(&host, 0, sizeof(t_hostent));  
  4691.   host.h_addr_list=he;
  4692.   he[0]=NULL;
  4693.   he[1]=NULL;  
  4694.   host.h_length=0;  
  4695.   */
  4696.   cache->iadr[0]='*';
  4697.   cache->iadr[1]='\0';
  4698.   
  4699.   /* get IP from the dns cache */
  4700.   hp = _hts_ghbn(cache, iadr, &buffer->hp);
  4701.   if (hp) {
  4702.     if (hp->h_length>0)
  4703.       return hp;
  4704.     else
  4705.       return NULL;    // entrΘe erronΘe (erreur DNS) dans le DNS
  4706.   } else {  // non prΘsent dans le cache dns, tester
  4707.     t_dnscache* c=cache;
  4708.     while(c->n) c=c->n;    // calculer queue
  4709.     
  4710. #if HTS_WIDE_DEBUG    
  4711.     DEBUG_W("gethostbyname\n");
  4712. #endif      
  4713. #if HDEBUG
  4714.     printf("gethostbyname (not in cache)\n");
  4715. #endif
  4716.     {
  4717.       unsigned long inetaddr;
  4718. #if HTS_WIN
  4719.       if ((inetaddr=inet_addr(iadr))==INADDR_NONE) {
  4720. #else
  4721.       if ((inetaddr=inet_addr(iadr))==(in_addr_t) -1 ) {
  4722. #endif        
  4723. #if DEBUGDNS 
  4724.         printf("resolving (not cached) %s\n",iadr);
  4725. #endif
  4726.         hp=vxgethostbyname(iadr, buffer);  // calculer IP host
  4727.       } else {     // numΘrique, convertir sans passer par le dns
  4728.         buffer->hp.h_addr_list[0]=(char*) &inetaddr;
  4729.         buffer->hp.h_length=4;
  4730.         hp=&buffer->hp;
  4731.       }
  4732.     }
  4733. #if HTS_WIDE_DEBUG    
  4734.     DEBUG_W("gethostbyname done\n");
  4735. #endif
  4736.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  4737.     if (cache->n!=NULL) {
  4738.       strcpybuff(cache->n->iadr,iadr);
  4739.       if (hp!=NULL) {
  4740.         memcpy(cache->n->host_addr, hp->h_addr_list[0], hp->h_length);
  4741.         cache->n->host_length=hp->h_length;
  4742.       } else {
  4743.         cache->n->host_addr[0]='\0';
  4744.         cache->n->host_length=0;  // non existant dans le dns
  4745.       }
  4746.       cache->n->n=NULL;
  4747.       return hp;
  4748.     } else {  // on peut pas noter, mais on peut renvoyer le rΘsultat
  4749.       return hp;
  4750.     }        
  4751.   }  // retour hp du cache
  4752. }
  4753.  
  4754. #else
  4755. HTS_INLINE t_hostent* hts_gethostbyname(char* iadr, t_fullhostent* buffer) {
  4756.   t_hostent* retour;
  4757. #if HTS_WIDE_DEBUG    
  4758.   DEBUG_W("gethostbyname (2)\n");
  4759. #endif
  4760. #if DEBUGDNS 
  4761.     printf("blocking method gethostbyname() in progress for %s\n",iadr);
  4762. #endif
  4763.   retour=vxgethostbyname(jump_identification(iadr), );
  4764. #if HTS_WIDE_DEBUG    
  4765.   DEBUG_W("gethostbyname (2) done\n");
  4766. #endif
  4767.   return retour;
  4768. }
  4769. #endif
  4770.  
  4771.  
  4772. // --- Tracage des mallocs() ---
  4773. #ifdef HTS_TRACE_MALLOC
  4774. //#define htsLocker(A, N) htsLocker(A, N)
  4775. #define htsLocker(A, N) do {} while(0)
  4776. static mlink trmalloc = {NULL,0,0,NULL};
  4777. static int trmalloc_id=0;
  4778. static PTHREAD_LOCK_TYPE* mallocMutex = NULL;
  4779. static void hts_meminit(void) {
  4780.   //if (mallocMutex == NULL) {
  4781.   //  mallocMutex = calloc(sizeof(*mallocMutex), 1);
  4782.   //  htsLocker(mallocMutex, -999);
  4783.   //}
  4784. }
  4785. void* hts_malloc(size_t len) {
  4786.   void* adr;
  4787.   hts_meminit();
  4788.   htsLocker(mallocMutex, 1);
  4789.   fassert(len > 0);
  4790.   adr = hts_xmalloc(len, 0);
  4791.   htsLocker(mallocMutex, 0);
  4792.   return adr;
  4793. }
  4794. void* hts_calloc(size_t len,size_t len2) {
  4795.   void* adr;
  4796.   hts_meminit();
  4797.   fassert(len > 0);
  4798.   fassert(len2 > 0);
  4799.   htsLocker(mallocMutex, 1);
  4800.   adr = hts_xmalloc(len, len2);
  4801.   htsLocker(mallocMutex, 0);
  4802.   memset(adr, 0, len * len2);
  4803.   return adr;
  4804. }
  4805. void* hts_strdup(char* str) {
  4806.   size_t size = str ? strlen(str) : 0;
  4807.   char* adr = (char*) hts_malloc(size + 1);
  4808.   fassert(adr != NULL);
  4809.   strcpy(adr, str ? str : "");
  4810.   return adr;
  4811. }
  4812. void* hts_xmalloc(size_t len,size_t len2) {
  4813.   mlink* lnk = (mlink*) calloc(1,sizeof(mlink));
  4814.   fassert(lnk != NULL);
  4815.   fassert(len > 0);
  4816.   fassert(len2 >= 0);
  4817.   if (lnk) {
  4818.     void*  r   = NULL;
  4819.     int size, bsize = sizeof(t_htsboundary);
  4820.     if (len2)
  4821.       size = len * len2;
  4822.     else
  4823.       size = len;
  4824.     size += ((bsize - (size % bsize)) % bsize);  /* check alignement */
  4825.     r = malloc(size + bsize*2);
  4826.     fassert(r != NULL);
  4827.     if (r) {
  4828.       * ( (t_htsboundary*) ((char*) r ) ) 
  4829.         = * ( (t_htsboundary*) ( (char*) r + size + bsize ) )
  4830.         = htsboundary;
  4831.       ((char*) r) += bsize;    /* boundary */
  4832.       lnk->adr = r;
  4833.       lnk->len = size;
  4834.       lnk->id = trmalloc_id++;
  4835.       lnk->next = trmalloc.next;
  4836.       trmalloc.next = lnk;
  4837.       return r;
  4838.     } else {
  4839.       free(lnk);
  4840.     }
  4841.   }
  4842.   return NULL;
  4843. }
  4844. void hts_free(void* adr) {
  4845.   mlink* lnk = &trmalloc;
  4846.   int bsize = sizeof(t_htsboundary);
  4847.   fassert(adr != NULL);
  4848.   if (!adr) {
  4849.     return;
  4850.   }
  4851.   htsLocker(mallocMutex, 1);
  4852.   while(lnk->next != NULL) {
  4853.     if (lnk->next->adr == adr) {
  4854.       mlink* blk_free=lnk->next;
  4855.       fassert(blk_free->id != -1);
  4856.       fassert( * ( (t_htsboundary*) ( (char*) adr - bsize ) ) == htsboundary );
  4857.       fassert( * ( (t_htsboundary*) ( (char*) adr + blk_free->len ) ) == htsboundary );
  4858.       lnk->next=lnk->next->next;
  4859.       free((void*) blk_free);
  4860.       //blk_free->id=-1;
  4861.       free((char*) adr - bsize);
  4862.       htsLocker(mallocMutex, 0);
  4863.       return;
  4864.     }
  4865.     lnk = lnk->next;
  4866.     fassert(lnk->next != NULL);
  4867.   }
  4868.   free(adr);
  4869.   htsLocker(mallocMutex, 0);
  4870. }
  4871. void* hts_realloc(void* adr,size_t len) {
  4872.   int bsize = sizeof(t_htsboundary);
  4873.   len += ((bsize - (len % bsize)) % bsize);  /* check alignement */
  4874.   if (adr != NULL) {
  4875.     mlink* lnk = &trmalloc;
  4876.     htsLocker(mallocMutex, 1);
  4877.     while(lnk->next != NULL)  {
  4878.       if (lnk->next->adr==adr) {
  4879.         {
  4880.           mlink* blk_free=lnk->next;
  4881.           fassert(blk_free->id != -1);
  4882.           fassert( * ( (t_htsboundary*) ( (char*) adr - bsize ) ) == htsboundary );
  4883.           fassert( * ( (t_htsboundary*) ( (char*) adr + blk_free->len ) ) == htsboundary );
  4884.         }
  4885.         adr = realloc((char*) adr - bsize, len + bsize * 2);
  4886.         fassert(adr != NULL);
  4887.         lnk->next->adr = (char*) adr + bsize;
  4888.         lnk->next->len = len;
  4889.         * ( (t_htsboundary*) ( (char*) adr ) ) 
  4890.           = * ( (t_htsboundary*) ( (char*) adr + len + bsize) ) 
  4891.           = htsboundary;
  4892.         htsLocker(mallocMutex, 0);
  4893.         return (char*) adr + bsize;
  4894.       }
  4895.       lnk = lnk->next;
  4896.       fassert(lnk->next != NULL);
  4897.     }
  4898.     htsLocker(mallocMutex, 0);
  4899.   }
  4900.   return hts_malloc(len);
  4901. }
  4902. mlink* hts_find(char* adr) {
  4903.   char* stkframe = (char*) &stkframe;
  4904.   mlink* lnk = &trmalloc;
  4905.   int bsize = sizeof(t_htsboundary);
  4906.   fassert(adr != NULL);
  4907.   if (!adr) {
  4908.     return NULL;
  4909.   }
  4910.   htsLocker(mallocMutex, 1);
  4911.   while(lnk->next != NULL) {
  4912.     if (adr >= lnk->next->adr && adr <= lnk->next->adr + lnk->next->len) {   /* found */
  4913.       htsLocker(mallocMutex, 0);
  4914.       return lnk->next;
  4915.     }
  4916.     lnk = lnk->next;
  4917.   }
  4918.   htsLocker(mallocMutex, 0);
  4919.   {
  4920.     int depl = (int) (adr - stkframe);
  4921.     if (depl < 0) depl = -depl;
  4922.     //fassert(depl < 512000);   /* near the stack frame.. doesn't look like malloc but stack variable */
  4923.     return NULL;
  4924.   }
  4925. }
  4926. // check the malloct() and calloct() trace stack
  4927. void  hts_freeall(void) {
  4928.   int bsize = sizeof(t_htsboundary);
  4929.   while(trmalloc.next) {
  4930. #if MEMDEBUG
  4931.     printf("* block %d\t not released: at %d\t (%d\t bytes)\n",trmalloc.next->id,trmalloc.next->adr,trmalloc.next->len);
  4932. #endif
  4933.     if (trmalloc.next->id != -1) {
  4934.       free((char*) trmalloc.next->adr - bsize);
  4935.     }
  4936.   }
  4937. }
  4938. #endif
  4939.  
  4940.  
  4941. // -- divers //
  4942.  
  4943. // cut path and project name
  4944. // patch also initial path
  4945. void cut_path(char* fullpath,char* path,char* pname) {
  4946.   path[0]=pname[0]='\0';
  4947.   if (strnotempty(fullpath)) {
  4948.     if ((fullpath[strlen(fullpath)-1]=='/') || (fullpath[strlen(fullpath)-1]=='\\'))
  4949.       fullpath[strlen(fullpath)-1]='\0';
  4950.     if (strlen(fullpath)>1) {
  4951.       char* a;
  4952.       while( (a=strchr(fullpath,'\\')) ) *a='/';     // remplacer par /
  4953.       a=fullpath+strlen(fullpath)-2;
  4954.       while( (*a!='/') && ( a > fullpath)) a--;
  4955.       if (*a=='/') a++;
  4956.       strcpybuff(pname,a);
  4957.       strncatbuff(path,fullpath,(int) (a - fullpath));
  4958.     }
  4959.   }
  4960. }
  4961.  
  4962.  
  4963.  
  4964. // -- Gestion protocole ftp --
  4965.  
  4966. #if HTS_WIN
  4967. int ftp_available(void) {
  4968.   return 1;
  4969. }
  4970. #else
  4971. int ftp_available(void) {
  4972.   return 1;   // ok!
  4973.   //return 0;   // SOUS UNIX, PROBLEMES
  4974. }
  4975. #endif
  4976.  
  4977.  
  4978. int hts_dgb_init = 0;
  4979. FILE* hts_dgb_init_fp = NULL;
  4980. static void hts_dgb(char* msg);
  4981. HTSEXT_API void hts_debug(int level) {
  4982.   hts_dgb_init = level;
  4983.   if (hts_dgb_init > 0) {
  4984.     hts_dgb("hts_debug() called");
  4985.   }
  4986. }
  4987. static void hts_dgb(char* msg) {
  4988.   if (hts_dgb_init > 0) {
  4989.     if (hts_dgb_init_fp == NULL) {
  4990. #ifdef _WIN32_WCE
  4991.       hts_dgb_init_fp = fopen("\\Temp\\hts-debug.txt", "wb");
  4992. #else
  4993.       hts_dgb_init_fp = fopen("hts-debug.txt", "wb");
  4994. #endif
  4995.       if (hts_dgb_init_fp != NULL) {
  4996.         fprintf(hts_dgb_init_fp, "* Creating file\r\n");
  4997.       }
  4998.     }
  4999.     if (hts_dgb_init_fp != NULL) {
  5000.       fprintf(hts_dgb_init_fp, "%s\r\n", msg);
  5001.       fflush(hts_dgb_init_fp);
  5002.     }
  5003.   }
  5004. }
  5005.  
  5006. HTSEXT_API int hts_init(void) {
  5007.   static int hts_init_ok = 0;
  5008.  
  5009.   hts_dgb("entering hts_init()");    /* debug */
  5010.  
  5011. #ifdef _WIN32_WCE
  5012. #ifndef HTS_CECOMPAT
  5013.   xceinit(L"");
  5014. #endif
  5015. #endif
  5016.  
  5017.   /* Init threads */
  5018.   if (!hts_init_ok) {
  5019.     htsthread_init();
  5020.   }
  5021.  
  5022.   /* Ensure external modules are loaded */
  5023.   hts_dgb("calling htspe_init()");    /* debug */
  5024.   htspe_init();
  5025.  
  5026.   /* MD5 Auto-test */
  5027.   {
  5028.     char digest[32 + 2];
  5029.     unsigned char* atest = (unsigned char*)"MD5 Checksum Autotest";
  5030.     digest[0] = '\0';
  5031.     domd5mem(atest, strlen(atest), digest, 1); /* a42ec44369da07ace5ec1d660ba4a69a */
  5032.     if (strcmp(digest, "a42ec44369da07ace5ec1d660ba4a69a") != 0) {
  5033.       int fatal_broken_md5 = 0;
  5034.       assertf(fatal_broken_md5);
  5035.     }
  5036.   }
  5037.  
  5038.   hts_dgb("initializing default wrappers");    /* debug */
  5039.   if (!hts_init_ok) {
  5040.     hts_init_ok = 1;
  5041.     // default wrappers
  5042.     htswrap_init();
  5043.     htswrap_add("init",htsdefault_init);
  5044.     htswrap_add("free",htsdefault_uninit);
  5045.     htswrap_add("start",htsdefault_start);
  5046.     htswrap_add("change-options",htsdefault_chopt);
  5047.     htswrap_add("end",htsdefault_end);
  5048.     htswrap_add("preprocess-html",htsdefault_preprocesshtml);
  5049.     htswrap_add("postprocess-html",htsdefault_postprocesshtml);
  5050.     htswrap_add("check-html",htsdefault_checkhtml);
  5051.     htswrap_add("loop",htsdefault_loop);
  5052.     htswrap_add("query",htsdefault_query);
  5053.     htswrap_add("query2",htsdefault_query2);
  5054.     htswrap_add("query3",htsdefault_query3);
  5055.     htswrap_add("check-link",htsdefault_check);
  5056.     htswrap_add("pause",htsdefault_pause);
  5057.     htswrap_add("save-file",htsdefault_filesave);
  5058.     htswrap_add("save-file2",htsdefault_filesave2);
  5059.     htswrap_add("link-detected",htsdefault_linkdetected);
  5060.     htswrap_add("link-detected2",htsdefault_linkdetected2);
  5061.     htswrap_add("transfer-status",htsdefault_xfrstatus);
  5062.     htswrap_add("save-name",htsdefault_savename);
  5063.     htswrap_add("send-header",htsdefault_sendheader);
  5064.     htswrap_add("receive-header",htsdefault_receiveheader);
  5065.   }
  5066.   
  5067.   hts_dgb("initializing SSL");    /* debug */
  5068. #if HTS_USEOPENSSL
  5069.   /*
  5070.   Initialize the OpensSSL library
  5071.   */
  5072.   if (!openssl_ctx && SSL_is_available) {
  5073.     if (SSL_load_error_strings) SSL_load_error_strings();
  5074.     SSL_library_init();
  5075.     ///if (SSL_load_error_strings)  SSL_load_error_strings();
  5076.     //if (ERR_load_crypto_strings) ERR_load_crypto_strings();
  5077.     // if (ERR_load_SSL_strings)    ERR_load_SSL_strings(); ???!!!
  5078.     // OpenSSL_add_all_algorithms();
  5079.     openssl_ctx = SSL_CTX_new(SSLv23_client_method());
  5080.     if (!openssl_ctx) {
  5081.       fprintf(stderr, "fatal: unable to initialize TLS: SSL_CTX_new(SSLv23_client_method)\n");
  5082.       abortLog("unable to initialize TLS: SSL_CTX_new(SSLv23_client_method)");
  5083.       assertf("unable to initialize TLS" == NULL);
  5084.     }
  5085.   }
  5086. #endif
  5087.   
  5088.   /* Init vars and thread-specific values */
  5089.   hts_dgb("initializing variables");    /* debug */
  5090.   hts_initvar();
  5091.   
  5092.   /* initialiser structcheck */
  5093.   // structcheck_init(1);
  5094.  
  5095.   hts_dgb("ending hts_init()");    /* debug */
  5096.   return 1;
  5097. }
  5098. HTSEXT_API int hts_uninit(void) {
  5099.   //htsthread_uninit();
  5100.   hts_cache_free(_hts_cache());
  5101.   hts_freevar();
  5102.   /* htswrap_free(); */
  5103.   return 1;
  5104. }
  5105.  
  5106. // defaut wrappers
  5107. void __cdecl htsdefault_init(void) {
  5108. }
  5109. void __cdecl htsdefault_uninit(void) {
  5110.   hts_freevar();
  5111. }
  5112. int __cdecl htsdefault_start(void* opt) {
  5113.   return 1; 
  5114. }
  5115. int __cdecl htsdefault_chopt(void* opt) {
  5116.   return 1;
  5117. }
  5118. int  __cdecl htsdefault_end(void) { 
  5119.   return 1; 
  5120. }
  5121. int __cdecl htsdefault_preprocesshtml(char** html,int* len,char* url_adresse,char* url_fichier) {
  5122.   return 1;
  5123. }
  5124. int __cdecl htsdefault_postprocesshtml(char** html,int* len,char* url_adresse,char* url_fichier) {
  5125.   return 1;
  5126. }
  5127. int __cdecl htsdefault_checkhtml(char* html,int len,char* url_adresse,char* url_fichier) {
  5128.   return 1;
  5129. }
  5130. int __cdecl htsdefault_loop(void* back,int back_max,int back_index,int lien_n,int lien_tot,int stat_time,hts_stat_struct* stats) {    // appelΘ α chaque boucle de HTTrack
  5131.   return 1;
  5132. }
  5133. char* __cdecl htsdefault_query(char* question) {
  5134.   return "";
  5135. }
  5136. char* __cdecl htsdefault_query2(char* question) {
  5137.   return "";
  5138. }
  5139. char* __cdecl htsdefault_query3(char* question) {
  5140.   return "";
  5141. }
  5142. int __cdecl htsdefault_check(char* adr,char* fil,int status) {
  5143.   return -1;
  5144. }
  5145. int __cdecl htsdefault_check_mime(char* adr,char* fil,char* mime,int status) {
  5146.   return -1;
  5147. }
  5148. void __cdecl htsdefault_pause(char* lockfile) {
  5149.   while (fexist(lockfile)) {
  5150.     Sleep(1000);
  5151.   }
  5152. }
  5153. void __cdecl htsdefault_filesave(char* file) {
  5154. }
  5155. void __cdecl htsdefault_filesave2(char* adr, char* file, char* sav, int is_new, int is_modified, int not_updated) {
  5156. }
  5157. int __cdecl htsdefault_linkdetected(char* link) {
  5158.   return 1;
  5159. }
  5160. int __cdecl htsdefault_linkdetected2(char* link, char* start_tag) {
  5161.   return 1;
  5162. }
  5163. int __cdecl htsdefault_xfrstatus(void* back) {
  5164.   return 1;
  5165. }
  5166. int __cdecl htsdefault_savename(char* adr_complete,char* fil_complete,char* referer_adr,char* referer_fil,char* save) {
  5167.   return 1;
  5168. }
  5169. int __cdecl htsdefault_sendheader(char* buff, char* adr, char* fil, char* referer_adr, char* referer_fil, htsblk* outgoing) {
  5170.   return 1;
  5171. }
  5172. int __cdecl htsdefault_receiveheader(char* buff, char* adr, char* fil, char* referer_adr, char* referer_fil, htsblk* incoming) {
  5173.   return 1;
  5174. }
  5175. // end defaut wrappers
  5176.  
  5177.  
  5178.  
  5179. // Fin
  5180.  
  5181.